2016-12-09 2 views
3

Ich stoße auf verwirrende und scheinbar widersprüchliche Regeln in Bezug auf rohe Strings. Betrachten Sie das folgende Beispiel:Raw Strings, Python und re, Normal vs Sonderzeichen

 
>>> text = 'm\n' 
>>> match = re.search('m\n', text) 
>>> print match.group() 
m 

>>> print text 
m 

Dies funktioniert, was in Ordnung ist.

 
>>> text = 'm\n' 
>>> match = re.search(r'm\n', text) 
>>> print match.group() 
m 

>>> print text 
m 

Auch dies funktioniert. Aber sollte das nicht einen Fehler verursachen, weil die rohe Zeichenkette die Zeichen m\n enthält und der tatsächliche Text eine neue Zeile enthält?

>>> text = r'm\n' 
>>> match = re.search(r'm\n', text) 
>>> print match.group() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'NoneType' object has no attribute 'group' 
>>> print text 
m\n 

Die oben genannten, wirft überraschenderweise einen Fehler, obwohl beide rohe Zeichenfolgen sind. Dies bedeutet, dass beide nur den Text m\n ohne Zeilenumbrüche enthalten.

>>> text = r'm\n' 
>>> match = re.search(r'm\\n', text) 
>>> print text 
m\n 
>>> print match.group() 
m\n 

Das obige funktioniert, überraschend. Warum muss ich den Backslash in der re.search umgehen, aber nicht im Text selbst?

Dann gibt es Backslash mit normalen Zeichen, die kein spezielles Verhalten haben:

>>> text = 'm\&' 
>>> match = re.search('m\&', text) 
>>> print text 
m\& 
>>> print match.group() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'NoneType' object has no attribute 'group' 

Dies passt nicht, obwohl sowohl das Muster und die Zeichenfolge fehlt Sonderzeichen.

In diesem Fall funktioniert keine Kombination von Raw-Zeichenfolgen (Text als Raw-Zeichenfolge, Muster als Raw-Zeichenfolge, beide oder keine).

Betrachten Sie jedoch das letzte Beispiel. Das Escapen in der Textvariablen 'm\\&' funktioniert nicht, aber das Entkommen im Muster funktioniert. Dies ist eine Parallele das Verhalten oben - noch seltsamer, fühle ich mich, wenn man bedenkt, dass \& keine besondere Bedeutung ist entweder Python oder re:

>>> text = 'm\&' 
>>> match = re.search(r'm\\&', text) 
>>> print text 
m\& 
>>> print match.group() 
m\& 

Mein Verständnis von rohen Strings ist, dass sie das Verhalten des umgekehrten Schrägstrich in Python hemmen . Für reguläre Ausdrücke ist dies wichtig, da re.search sein eigenes internes Backslash-Verhalten anwenden und Konflikte mit Python vermeiden kann. In Situationen wie dem oben genannten, in denen Backslash effektiv nichts bedeutet, bin ich mir nicht sicher, warum dies notwendig erscheint. Schlimmer noch, ich verstehe nicht, warum ich Backslash für das Muster brauche, aber nicht den Text, und wenn ich beide eine rohe Zeichenfolge mache, scheint es nicht zu funktionieren.

The docs bieten nicht viel Anleitung in dieser Hinsicht. Sie konzentrieren sich auf Beispiele mit offensichtlichen Problemen, wie '\section', wobei \s ein Meta-Zeichen ist. Auf der Suche nach einer vollständigen Antwort, um unvorhergesehenes Verhalten wie dieses zu verhindern.

+0

Es gibt nichts zu überraschen. 'r'm \ n 'hat die Länge 3 (' m', '' '' '' '' '' '' '' '' '' '} Der 'r'm \ n'' Regex entspricht 2 Zeichenketten,' m' + Newline. –

+0

Das macht Ihre Frage zu einem Betrogenen von http://StackOverflow.com/Questions/22937618/Reference-What-Does-this-regex-mean. Das 'r '\ n'' ist ein LF-passendes Muster. –

Antwort

0
text = r'm\n' 
match = re.search(r'm\\n', text) 

Erste Zeile mit r Anschläge Python von \n als einziges Byte zu interpretieren.

Zweite Zeile r mit spielt die gleiche Rolle wie first.Using \ regex verhindert, dass die Interpretation als \n .Regex auch \ wie \s verwendet, \d.

Die folgenden Zeichen sind die Meta-Zeichen, die eine besondere Bedeutung für den regulären Ausdruck Suchsyntax geben:

\ Backslash-Escape-Zeichen. Der Backslash gibt dem folgenden Zeichen eine besondere Bedeutung. Zum Beispiel steht die Kombination "\ n" für den Zeilenumbruch, eines der Steuerzeichen. Die Kombination "\ w" steht für ein "Wort" -Zeichen, eine der Komfort-Escape-Sequenzen, während "\ 1" eines der Ersatz-Sonderzeichen ist. Beispiel: Die Regex "aa \ n" versucht, zwei aufeinanderfolgende "a" s am Ende einer Zeile, einschließlich der Newline-Zeichen selbst zu entsprechen. Beispiel: "a +" entspricht "a +" und nicht eine Folge von eins oder "a" s.

+0

@GHH '\\' ist En-Escape-Zeichen.Sie wollen, dass Sie übereinstimmen, dass Sie '\\' 'verwenden müssen. Sie können eine Zeichenfolge' a \\ 'in Python nicht definieren – vks

+0

Danke, ich sehe die Verwirrung:' \ n 'hat auch eine besondere Bedeutung in Regex. Aber nehmen Sie die folgende Situation: Text und Muster = 'r'm \ k''. Dies wirft auch einen Fehler auf. Was ist mit Situationen, in denen 'r \ [was auch immer]' definitiv ** nicht speziell in Python oder re ist? Warum muss ich immer noch dem Backslash entkommen? – GHH

+0

@GHH weil '\\' selbst ein Sonderzeichen ist und wenn du es im wörtlichen Sinne verwendest, musst du es für den Regex-Interpreter nicht python – vks

0

Um die interne Darstellung der Saiten Sie verwirrt sind dabei, zu verstehen. Ich würde Ihnen empfehlen, repr und len eingebaute Funktionen zu verwenden. Mit diesen werden Sie in der Lage sein, genau zu verstehen, wie die Strings sind, und Sie werden nicht mehr mit dem Mustervergleich verwechselt werden, weil Sie die interne Repräsentation genau kennen. Zum Beispiel, sagen wir, Sie die Saiten analize wollen sind Sie Probleme mit haben:

use_cases = [ 
    'm\n', 
    r'm\n', 
    'm\\n', 
    r'm\\n', 
    'm\&', 
    r'm\&', 
    'm\\&', 
    r'm\\&', 
] 

for u in use_cases: 
    print('-' * 10) 
    print(u, repr(u), len(u)) 

Der Ausgang wäre:

---------- 
m 
'm\n' 2 
---------- 
m\n 'm\\n' 3 
---------- 
m\n 'm\\n' 3 
---------- 
m\\n 'm\\\\n' 4 
---------- 
m\& 'm\\&' 3 
---------- 
m\& 'm\\&' 3 
---------- 
m\& 'm\\&' 3 
---------- 
m\\& 'm\\\\&' 4 

So können Sie genau die Unterschiede zwischen normalen/raw Strings sehen.

+0

Cooler Trick. Ich werde das definitiv benutzen. Vielen Dank. – GHH

1

In dem regulären Python-String, 'm\n', die \n stellt ein einzelnes Newline-Zeichen, während in dem rohen String r'm\n' die \ und n nur selbst sind. So weit, so einfach.

Wenn Sie die Zeichenfolge 'm\n' als Muster re.search() passieren, vorbei sind Sie ein zwei Zeichenfolge (m von Newline gefolgt) und re wird gerne gehen und Instanzen dieser zwei Zeichenfolge für Sie zu finden.

Wenn Sie die dreistellige Zeichenfolge übergeben r'm\n', das re Modul selbst interpretiert die beiden Zeichen \n als die besondere Bedeutung haben „entsprechen einem Newline-Zeichen“, so dass das ganze Muster bedeutet „eine m entsprechen gefolgt durch einen Zeilenumbruch ", wie zuvor.

In Ihrem dritten Beispiel, da die Zeichenfolge r'm\n' nicht eine neue Zeile enthält, gibt es keine Übereinstimmung:

>>> text = r'm\n' 
>>> match = re.search(r'm\n', text) 
>>> print(match) 
None 

Mit dem Muster r'm\\n', sind Sie zwei tatsächliche Schrägstriche zu re.search() vorbei, und wieder, Das Modul re selbst interpretiert den doppelten Backslash als "Übereinstimmung mit einem einzelnen Backslash-Zeichen".

Im Fall von 'm\&' läuft etwas etwas anderes. Python behandelt den umgekehrten Schrägstrich als reguläres Zeichen, da er nicht Teil einer Escape-Sequenz ist. re, auf der anderen Seite, einfach die \ ablegt, so ist das Muster effektiv m&.Sie können sehen, dass dies durch die Prüfung der Muster gegen 'm&' wahr ist:

>>> re.search('m\&', 'm&').group() 
'm&' 

nach wie vor eine Verdoppelung der Backslash re Tells für einen tatsächlichen Backslash suchen:

>>> re.search(r'm\\&', 'm\&').group() 
'm\\&' 

... und nur zu die Dinge etwas verwirrender zu machen, wird der einzelne Backslash von Python verdoppelt dargestellt. Sie können sehen, dass es durch das Drucken es tatsächlich ein einzelner Backslash ist:

>>> print(re.search(r'm\\&', 'm\&').group()) 
m\& 
+0

Danke dafür! Ich weiß jetzt, dass sich ein Backslash in Python nur wie ein Sonderzeichen verhält, wenn er vor bestimmten Zeichen steht.Das ist der Grund, warum 'pattern = r'm \\ & '' sowohl mit text = r'm \ &' 'als auch mit text = r'm \\ & 'übereinstimmt. In Regex ist Backslash jedoch immer ein Sonderzeichen, unabhängig davon, ob es das Verhalten des folgenden Zeichens (wie '\ w') ändert oder nicht (wie' \ & '). Wenn ich also nur einen normalen Rückschritt haben möchte, muss ich immer in Regex entkommen, obwohl dies im normalen Python manchmal optional ist. – GHH

0

Um es in einfachen Worten zu erklären, \<character> hat eine besondere Bedeutung in regulären Ausdrücken. Zum Beispiel \s für Leerzeichen, \d für Dezimalstellen, \n für new-line Zeichen usw.

Wenn Sie eine Zeichenfolge als

s = 'foo\n' 

Diese Zeichenfolge enthält die Zeichen definieren f, o, o und die Zeilenwechselzeichen (Länge 4).

Wenn jedoch eine rohe Zeichenfolge definieren:

s = r'foo\n' 

Dieser String enthält die Zeichen f, o, o, \ und n (Länge 5).

Wenn Sie eine Regexp mit Raw \n (d. H. r'\n') kompilieren, werden alle neuen Zeilen übereinstimmen. In ähnlicher Weise wird nur das Zeichen für die neue Zeile verwendet (d. H. '\n'), es wird mit Zeichen für neue Zeilen übereinstimmen, genau wie a mit a und so weiter.

Sobald Sie dieses Konzept verstehen, sollten Sie in der Lage sein, den Rest herauszufinden.

Um ein bisschen weiter zu erarbeiten. Um den umgekehrten Schrägstrich \ unter Verwendung von Regex abzugleichen, ist der gültige reguläre Ausdruck\\, was in Python r'\\' oder sein Äquivalent '\\\\' wäre.