2015-11-07 24 views
8

Jestem mylony z odwrotnym ukośnikiem w wyrażeniach regularnych. W regexu \ ma specjalne znaczenie, np. \d oznacza cyfrę dziesiętną. Jeśli dodasz ukośnik odwrotny przed ukośnikiem odwrotnym, to specjalne znaczenie zostanie utracone. W regex-howto można przeczytać:Ukośniki w wyrażeniach regularnych w języku Python

Być może najważniejszym Metaznak jest backslash, \. Podobnie jak w literałach napisanych w Pythonie, ukośnik odwrotny może być poprzedzony różnymi znakami, które sygnalizują różne sekwencje specjalne. Używa się go również do unikania wszystkich metaznaków, dzięki czemu można je dopasować do wzorców; na przykład, jeśli chcesz dopasować [ lub \, możesz poprzedzić je ukośnikiem odwrotnym, aby usunąć ich specjalne znaczenie: \[ lub \\.

Więc print(re.search('\d', '\d')) daje None ponieważ \d dopasowuje dowolną cyfrę dziesiętną, ale nie ma nikogo w \d.

Teraz oczekiwałbym, że print(re.search('\\d', '\d')) będzie pasował do \d, ale odpowiedzią jest nadal None.

Tylko print(re.search('\\\d', '\d')) podaje jako wynik <_sre.SRE_Match object; span=(0, 2), match='\\d'>.

Czy ktoś ma wyjaśnienie?

+0

http://stackoverflow.com/questions/24085680/why-do-backslashes-appear-twice – fghj

+0

Możliwy duplikat [Nie można uciec przed ukośnikiem z wyrażeniem regularnym?] (Https://stackoverflow.com/questions/4025482/ cant-escape-the-backslash-with-regex) – tripleee

Odpowiedz

8

Zamieszanie wynika z faktu, że znak ukośnika odwrotnego \ służy jako ucieczka na dwóch różnych poziomach. Po pierwsze, sam interpreter Pythona wykonuje zastępstwa dla \, zanim moduł re kiedykolwiek zobaczy twój łańcuch. Na przykład \n jest konwertowany na znak nowego wiersza, \t jest konwertowany na znak tabulacji, itp. Aby uzyskać rzeczywisty znak \, można również uciec, więc \\ podaje jedną znak \. Jeśli postać występująca po \ nie jest rozpoznawanym znakiem ewakuacyjnym, to \ jest traktowany jak każda inna postać i przechodzi przez nią, ale nie polecam w zależności od tego. Zamiast tego zawsze unikaj znaków \, podwajając je, tj. \\.

Jeśli chcesz zobaczyć, jak Python rozszerza twój łańcuch znaków, po prostu wypisz ciąg. Na przykład:

s = 'a\\b\tc' 
print s 

Jeśli s jest częścią zbiorczego typu danych, np.listę lub krotkę, a jeśli wydrukujesz ten agregat, Python będzie zawierał ciąg w pojedynczych cudzysłowach i będzie zawierał znaki specjalne \ (w formie kanonicznej), więc należy pamiętać o tym, jak drukowany jest twój ciąg. Jeśli po prostu wpiszesz cudzysłowy do interpretera, wyświetli go również w cudzysłowach z znakami "\".

Kiedy już wiesz, jak kodowany jest twój ciąg, możesz pomyśleć o tym, co zrobi moduł re. Na przykład, jeśli chcesz uciec \ w ciągu, który przekazujesz do modułu re, musisz przekazać \\ do re, co oznacza, że ​​będziesz musiał użyć \\\\ w cytowanym ciągu liter Pythona. Łańcuch w języku Python kończy się na \\, a moduł re traktuje to jako pojedynczą literę o nazwie \.

Alternatywnym sposobem dodawania znaków \ w łańcuchach w języku Python jest użycie ciągów ciągłych, np. r'a\b' jest odpowiednikiem "a\\b".

+0

Bardzo dziękuję za wszystkie odpowiedzi. Byłem świadomy r "...", a także przejrzałem dokumentację re, ale nie zrozumiałem. Teraz wszystko jest lepsze. "\ b" jest specjalne dla interpretera Pythona, ponieważ znajduje "\". '\\ b' eliminuje interpretację interpretera python kończącego się ciągiem '\ b'. Jest to rozpoznawane przez moduł re jako skrót dla cyfry dziesiętnej. '\\\ b' również pokonuje interpretację modułu re, a kończy się ciągiem "\ b". – tobmei05

+0

Dziękujemy! 4 ukośniki, jak miło. Więc nie ma literalnych ciągów w pytonie? Mam na myśli, na przykład, w PHP, jeśli używasz pojedynczych cudzysłowów, to nie są dokonywane żadne zmiany. – Rolf

3

Parsowanie własnego fragmentu w Pythonie (częściowo) wchodzi na twoją drogę.

Jeśli chcesz zobaczyć, co re widzi, typ

print '\d' 
print '\\d' 
print '\\\d' 

na wierszu poleceń Pythona. Zobaczysz, że obydwa te parametry dają \d i \\d\d, z których ostatnia jest obsługiwana przez parser napisów w języku Python.

Jeśli chcesz uniknąć kłopotów z tymi, użyj nieprzetworzonych ciągów zgodnie z sugestią użytkownika re module documentation: spowoduje to, że \\d będzie widziane przez moduł RE.

+2

https://docs.python.org/2/library/re.html zobacz sekcję '\' – Alex

+1

@Alex Dzięki, dodałem link do odpowiedzi. – glglgl

4

Znak r przed wyrażeniem regularnym mówi w wywołaniu wyszukiwania() określa, że ​​wyrażenie regularne jest nieprzetworzonym łańcuchem znaków. Dzięki temu ukośniki odwrotne mogą być używane w wyrażeniu regularnym jako zwykłe znaki, a nie w sekwencji unikowej znaków. Pozwól mi wyjaśnić ...

Zanim metoda wyszukiwania w module re przetwarza łańcuchy, które są do niej przekazywane, interpreter Pythona wykonuje wstępne przejście przez ciąg znaków. Jeśli w ciągu występują ciągi odwrotne, interpreter w języku Python musi zdecydować, czy każdy z nich jest częścią sekwencji wyjściowej w języku Python (np. \ N lub \ t), czy też nie.

Uwaga: w tym momencie Python nie dba o to, czy "\" jest metaznakiem wyrażenia regularnego.

Po znaku "\" po rozpoznanym znaku interpunkcyjnym języka Python (t, n itp.), Odwrotny ukośnik i znak escape są zamieniane na rzeczywisty znak Unicode lub 8-bitowy. Na przykład "\ t" zostanie zastąpione przez znak ASCII dla tabulatora. W przeciwnym razie jest przekazywana i interpretowana jako znak "\".

Należy rozważyć następujące kwestie.

>>> s = '\t' 
>>> print ("[" + s + "]") 
>>> [  ]   // an actual tab character after preprocessing 

>>> s = '\d' 
>>> print ("[" + s + "]") 
>>> [\d]    // '\d' after preprocessing 

Czasami chcemy umieścić w ciąg ciąg znaków, który zawiera „\” bez niego są interpretowane przez Python jako sekwencji ucieczki. W tym celu unikamy "\" z "\". Teraz, gdy Python widzi "\", zastępuje dwa tylne ukośniki pojedynczym znakiem "\".

>>> s = '\\t' 
>>> print ("[" + s + "]") 
>>> [\t]    // '\t' after preprocessing 

Po przejściu przez interpreter języka Python obu łańcuchów, są one przekazywane do metody wyszukiwania modułu re. Metoda wyszukiwania analizuje łańcuch wyrażenia regularnego, aby zidentyfikować meta-znaki wyrażenia regularnego.

Teraz "\" jest również specjalnym meta-znakiem wyrażenia regularnego i jest interpretowane jako jedno, O ile nie jest ono zmienione w czasie wykonywania metody re search().

Rozważ następujące połączenie.

>>> match = re.search('a\\t','a\\t')  //Match is None 

Tutaj mecz jest Brak. Czemu? Przyjrzyjmy się ciągom znaków po tym, jak interpreter Pythona przejdzie.

String 1: 'a\t' 
String 2: 'a\t' 

Dlaczego więc mecz jest równy None?Gdy search() interpretuje String 1, ponieważ jest to wyrażenie regularne, ukośnik odwrotny jest interpretowany jako meta-znak, a nie jako zwykły znak. Odwrotny ukośnik w łańcuchu 2 nie jest jednak wyrażeniem regularnym i został już przetworzony przez interpreter języka Python, więc jest interpretowany jako zwykły znak.

Metoda search() szuka 'escape-t' w ciągu znaków "a \ t", które nie są zgodne.

Aby to naprawić, możemy powiedzieć, że metoda search() nie interpretuje "\" jako meta-znaku. Możemy to zrobić, uciekając przed tym.

Rozważ następujące połączenie.

>>> match = re.search('a\\\\t','a\\t')   // Match contains 'a\t' 

Ponownie, pozwala spojrzeć na ciągi po tym, jak interpreter Pythona wykonał przekaz.

String 1: 'a\\t' 
String 2: 'a\t' 

Teraz, gdy metoda search() przetwarza wyrażenie regularne, to widzi, że drugi backslash jest uciekł przez pierwszy i nie powinien być traktowany jako meta-znaków. Dlatego interpretuje ciąg jako "a \ t", który pasuje do ciągu znaków 2.

Alternatywny sposób wyszukiwania() jako "znak" oznacza umieszczenie r przed wyrażeniem regularnym. Dzięki temu interpreter języka Python NIE przetwarza ciągu.

Rozważ to.

>>> match = re.search(r'a\\t','a\\t')   // match contains 'a\t' 

Tutaj interpreter języka Python nie modyfikuje pierwszego ciągu, ale przetwarza drugi ciąg znaków. Struny przekazywane do search() są:

String 1: 'a\\t' 
String 2: 'a\t' 

Podobnie jak w poprzednim przykładzie, wyszukiwarka interpretuje „\” jako pojedynczy znak „\” a nie meta-znaków, co odpowiada sznurkiem 2.

Powiązane problemy