Was genau ist ein "roher String-Regex" und wie können Sie ihn verwenden?

73

Aus der Python-Dokumentation zu Regex bezüglich des '\'Charakters:

Die Lösung besteht darin, die rohe String-Notation von Python für Muster mit regulären Ausdrücken zu verwenden. Backslashes werden in einem Zeichenfolgenliteral mit dem Präfix nicht speziell behandelt 'r'. So r"\n"ist eine Zwei-Zeichenkette enthält '\'und 'n', während "\n"ein Eins-Zeichenfolge eine neue Zeile enthält. Normalerweise werden Muster in Python-Code unter Verwendung dieser rohen Zeichenfolgennotation ausgedrückt.

Was ist diese rohe String-Notation? Wenn Sie ein Rohzeichenfolgenformat verwenden, bedeutet dies, dass "*"es sich eher um ein Literal als um einen Null-oder-Mehr-Indikator handelt? Das kann natürlich nicht richtig sein, sonst würde Regex seine Kraft völlig verlieren. Aber wenn es sich um eine rohe Zeichenfolge handelt, wie erkennt es dann Zeilenumbrüche, wenn "\n"es sich buchstäblich um einen Backslash und einen handelt "n"?

Ich folge nicht.

Für Kopfgeld bearbeiten:

Ich versuche zu verstehen, wie ein Regex für rohe Zeichenfolgen mit Zeilenumbrüchen, Tabulatoren und Zeichensätzen übereinstimmt, z. B. \wfür Wörter oder \dZiffern oder so weiter, wenn rohe Zeichenfolgenmuster Backslashes nicht als etwas anderes als gewöhnliche Zeichen erkennen. Ich könnte wirklich einige gute Beispiele gebrauchen.

temporärer_Benutzername
quelle
11
Rohe Zeichenfolgen haben etwas damit zu tun, wie Python Zeichenfolgen verarbeitet. Es hat nichts mit regulären Ausdrücken zu tun. Aufgrund ihrer Eigenschaften ist es nur praktisch, sie für den regulären Ausdruck zu verwenden.
Felix Kling

Antworten:

92

Zarkonnens Antwort beantwortet Ihre Frage, aber nicht direkt. Lassen Sie mich versuchen, direkter zu sein und zu sehen, ob ich das Kopfgeld von Zarkonnen bekommen kann.

Sie werden dies vielleicht leichter verstehen, wenn Sie die Begriffe "Raw String Regex" und "Raw String Patterns" nicht mehr verwenden. Diese Begriffe verbinden zwei separate Konzepte: die Darstellungen einer bestimmten Zeichenfolge im Python-Quellcode und den regulären Ausdruck, den diese Zeichenfolge darstellt.

In der Tat ist es hilfreich, sich diese als zwei verschiedene Programmiersprachen mit jeweils eigener Syntax vorzustellen. Die Python-Sprache verfügt über Quellcode, der unter anderem Zeichenfolgen mit bestimmten Inhalten erstellt und das reguläre Ausdruckssystem aufruft. Das System mit regulären Ausdrücken verfügt über Quellcode, der sich in Zeichenfolgenobjekten befindet und mit Zeichenfolgen übereinstimmt. Beide Sprachen verwenden Backslash als Escape-Zeichen.

Verstehen Sie zunächst, dass eine Zeichenfolge eine Folge von Zeichen ist (dh Bytes oder Unicode-Codepunkte; die Unterscheidung spielt hier keine große Rolle). Es gibt viele Möglichkeiten, eine Zeichenfolge im Python-Quellcode darzustellen. Eine rohe Zeichenfolge ist einfach eine dieser Darstellungen. Wenn zwei Darstellungen zu derselben Zeichenfolge führen, erzeugen sie ein gleichwertiges Verhalten.

Stellen Sie sich eine 2-stellige Zeichenfolge vor, die aus dem Backslash- Zeichen gefolgt vom n- Zeichen besteht. Wenn Sie wissen, dass der Zeichenwert für Backslash 92 und für n 110 ist, generiert dieser Ausdruck unsere Zeichenfolge:

s = chr(92)+chr(110)
print len(s), s

2 \n

Die herkömmliche Python-String-Notation "\n"generiert diesen String nicht. Stattdessen wird eine einstellige Zeichenfolge mit einem Zeilenumbruchzeichen generiert. Die Python-Dokumente 2.4.1. String-Literale sagen: "Das Backslash-Zeichen (\) wird verwendet, um Zeichen zu maskieren, die ansonsten eine besondere Bedeutung haben, z. B. Zeilenumbruch, Backslash selbst oder Anführungszeichen."

s = "\n"
print len(s), s

1 
 

(Beachten Sie, dass die neue Zeile in diesem Beispiel nicht sichtbar ist. Wenn Sie jedoch genau hinschauen, wird nach der "1" eine leere Zeile angezeigt.)

Um unsere zweistellige Zeichenfolge zu erhalten, müssen wir ein anderes Backslash- Zeichen verwenden, um der besonderen Bedeutung des ursprünglichen Backslash- Zeichens zu entgehen :

s = "\\n"
print len(s), s

2 \n

Was ist, wenn Sie Zeichenfolgen darstellen möchten, die viele Backslash- Zeichen enthalten? Python-Dokumente 2.4.1. String-Literale fahren fort: "String-Literalen kann optional ein Buchstabe 'r' oder 'R' vorangestellt werden. Solche Strings werden als Raw-Strings bezeichnet und verwenden unterschiedliche Regeln für die Interpretation von Backslash-Escape-Sequenzen." Hier ist unsere zweistellige Zeichenfolge mit roher Zeichenfolgendarstellung:

s = r"\n"
print len(s), s

2 \n

Wir haben also drei verschiedene Zeichenfolgendarstellungen, die alle dieselbe Zeichenfolge oder Zeichenfolge enthalten:

print chr(92)+chr(110) == "\\n" == r"\n"
True

Wenden wir uns nun den regulären Ausdrücken zu. Die Python-Dokumente, 7.2. re- Bei Operationen mit regulären Ausdrücken heißt es: "Reguläre Ausdrücke verwenden das Backslash-Zeichen ('\'), um Sonderformen anzugeben oder die Verwendung von Sonderzeichen zu ermöglichen, ohne ihre besondere Bedeutung aufzurufen. Dies kollidiert mit Pythons Verwendung desselben Zeichens für denselben Zweck in String-Literale ... "

Wenn Sie ein Python-Objekt mit regulären Ausdrücken möchten, das einem Zeilenumbruchzeichen entspricht, benötigen Sie eine 2-stellige Zeichenfolge, die aus dem Backslash- Zeichen gefolgt vom n- Zeichen besteht. Die folgenden Codezeilen setzen prog auf ein Objekt mit regulären Ausdrücken, das ein Zeilenumbruchzeichen erkennt:

prog = re.compile(chr(92)+chr(110))
prog = re.compile("\\n")
prog = re.compile(r"\n")

Warum also "werden Muster normalerweise in Python-Code unter Verwendung dieser rohen String-Notation ausgedrückt." ? Weil reguläre Ausdrücke häufig statische Zeichenfolgen sind, die bequem als Zeichenfolgenliterale dargestellt werden. Aus den verschiedenen verfügbaren Zeichenfolgenliteralnotationen sind Rohzeichenfolgen eine bequeme Wahl, wenn der reguläre Ausdruck ein Backslash- Zeichen enthält.

Fragen

F : Was ist mit dem Ausdruck re.compile(r"\s\tWord")? A : Es ist einfacher zu verstehen, wenn Sie die Zeichenfolge von der Zusammenstellung regulärer Ausdrücke trennen und separat verstehen.

s = r"\s\tWord"
prog = re.compile(s)

Die Zeichenfolge senthält acht Zeichen: einen Backslash , ein s , einen Backslash , ein t und dann vier Zeichen Word.

F : Was passiert mit den Tabulator- und Leerzeichen? A : Auf der Python-Sprachebene hat die Zeichenfolge skeine Tabulator- und Leerzeichen . Es beginnt mit vier Zeichen: Backslash , s , Backslash , t . Das System für reguläre Ausdrücke behandelt diese Zeichenfolge unterdessen als Quellcode in der Sprache für reguläre Ausdrücke. Dabei bedeutet dies "Übereinstimmung mit einer Zeichenfolge, die aus einem Leerzeichen, einem Tabulatorzeichen und den vier Zeichen besteht Word.

F : Wie passen Sie zu diesen, wenn dies als Backlash-s und Backslash-t behandelt wird? A : Vielleicht ist die Frage klarer, wenn die Wörter "Sie" und "das" spezifischer gemacht werden: Wie passt das System der regulären Ausdrücke zu den Ausdrücken "Backlash-s" und "Backslash-t"? Als 'beliebiges Leerzeichen' und als ' Tabulatorzeichen '.

F : Oder was ist, wenn Sie die 3-stellige Zeichenfolge Backslash-n-Newline haben? A : In der Python-Sprache kann die 3-stellige Zeichenfolge Backslash-n-Newline als herkömmliche Zeichenfolge "\\n\n"oder als rohe plus herkömmliche Zeichenfolge r"\n" "\n"oder auf andere Weise dargestellt werden. Das System für reguläre Ausdrücke entspricht dem Backslash-n-Newline mit drei Zeichenfolgen, wenn zwei aufeinanderfolgende Zeilenumbrüche gefunden werden .

NB Alle Beispiele und Dokumentverweise beziehen sich auf Python 2.7.

Update : Eingeschlossene Klarstellungen aus den Antworten von @Vladislav Zorov und @ m.buettner sowie aus der Folgefrage von @Aerovistae.

Jim DeLaHunt
quelle
Was ist mit re.compile (r "\ s \ tWord")? Was passiert mit den Tabulator- und Leerzeichen? Wie passen Sie zu diesen, wenn dies als Backlash-s und Backslash-t behandelt wird? Oder was ist, wenn Sie die 3-stellige Zeichenfolge Backslash-n-Newline haben? Was dann?
temporärer_Benutzername
1
@Aerovistae Es wird Backslash s behandelt, Backslash t beim Kompilieren der Zeichenfolge. Diese vier Zeichen werden an die Regex-Engine übergeben, die die Zeichenfolge analysiert und weiß, dass sie mit einem Leerzeichen und einem Tabulator übereinstimmen muss. Wenn Sie eine normale (nicht rohe) Zeichenfolge verwendet hätten, würde \ s wahrscheinlich wie sin der Zeichenfolge enden und \tzu einem Tabulatorzeichen werden. Jetzt werden nur noch zwei Zeichen an die Regex-Engine übergeben. Während die Engine möglicherweise noch mit einem Tabulatorzeichen übereinstimmen kann, versucht sie nun, ein vorangestelltes Zeichen zu finden s.
Martin Ender
2
ord(92)wird nur ein erhöhen TypeError, weil 92es kein String ist. Sie meinten wahrscheinlich chr(92)(oder vielleicht unichr(92))?
abarnert
Danke, @abarnert! Ich habe den Code getestet und festgestellt, dass ich ord () anstelle von chr () eingegeben habe. Ich glaube, ich habe diese Korrektur nicht auf die Antwort zurückgeführt. Meine Antwort wurde korrigiert.
Jim DeLaHunt
2
Hey @JimDeLaHunt Ich wollte sagen, dass ich ein Jahr später zurückgekommen bin und dies gelesen habe, nachdem ich dieses rohe String-Zeug endlich in einem anderen Kontext verstanden habe, und ich kann jetzt sehen, dass Ihre Erklärung wirklich klar ist. Ich denke, zu der Zeit hatte ich gerade eine große mentale Blockade ... jetzt unterrichte ich eine Klasse darüber! Danke noch einmal.
temporärer_Benutzername
16

Die meisten dieser Fragen enthalten viele Wörter, und möglicherweise ist es schwierig, die Antwort auf Ihre spezifische Frage zu finden.

Wenn Sie eine reguläre Zeichenfolge verwenden und ein Muster wie "\ t" an den RegEx-Parser übergeben, übersetzt Python dieses Literal in einen Puffer mit dem darin enthaltenen Tab-Byte (0x09).

Wenn Sie eine unformatierte Zeichenfolge verwenden und ein Muster wie r "\ t" an den RegEx-Parser übergeben, führt Python keine Interpretation durch und erstellt einen Puffer mit zwei Bytes: '\' und 't'. (0x5c, 0x74).

Der RegEx-Parser weiß, was mit der Sequenz '\ t' zu tun ist - er vergleicht diese mit einer Registerkarte. Es weiß auch, was mit dem Zeichen 0x09 zu tun ist - das entspricht auch einer Registerkarte. Die Ergebnisse sind größtenteils nicht zu unterscheiden.

Der Schlüssel zum Verständnis des Geschehens liegt also darin, zu erkennen, dass hier zwei Parser verwendet werden. Der erste ist der Python-Parser, der Ihr String-Literal (oder Raw-String-Literal) in eine Folge von Bytes übersetzt. Der zweite ist Pythons Parser für reguläre Ausdrücke und konvertiert eine Folge von Bytes in einen kompilierten regulären Ausdruck.

Geoff Gerrietts
quelle
5

Das Problem bei der Verwendung einer normalen Zeichenfolge zum Schreiben von regulären Ausdrücken, die a enthalten, \besteht darin, dass Sie am Ende \\für jede schreiben müssen \. Also die String-Literale "stuff\\things"und r"stuff\things"produzieren den gleichen String. Dies ist besonders nützlich, wenn Sie einen regulären Ausdruck schreiben möchten, der mit Backslashes übereinstimmt.

Mit normalen Strings, einen regulären Ausdruck, der Zeichenfolge entspricht \wäre "\\\\"!

Warum? Weil wir \zweimal entkommen müssen : einmal für die Syntax des regulären Ausdrucks und einmal für die String-Syntax.

Sie können dreifache Anführungszeichen verwenden, um Zeilenumbrüche wie folgt einzuschließen:

r'''stuff\
things'''

Beachten Sie, dass Python normalerweise \-newline als Zeilenfortsetzung behandelt , dies ist jedoch bei rohen Zeichenfolgen nicht der Fall. Beachten Sie auch, dass Backslashes immer noch Anführungszeichen in rohen Zeichenfolgen entgehen, aber in sich selbst verbleiben. Das rohe String-Literal r"\""erzeugt also den String \". Dies bedeutet, dass Sie ein Raw-String-Literal nicht mit einem Backslash beenden können.

Siehe den lexikalische Analyse Abschnitt der Python - Dokumentation für weitere Informationen.

Zarkonnen
quelle
1
Nicht wirklich \\ für jeden \. '\ d' wird als Schrägstrich (?) interpretiert, gefolgt von d.
nhahtdh
2
@ Aerovistae: Verwenden r'''something<enter>onnewline'''. <enter>bedeutet, drücken Sie die Eingabetaste. Nicht gerade hübsch, also können Sie hier wahrscheinlich die Verkettung von Zeichenfolgen verwenden?
nhahtdh
2
Aufgrund des Umgangs mit rohen Zeichenfolgen liegt tatsächlich r"stuff\"ein Fehler vor.
Ignacio Vazquez-Abrams
@ IgnacioVazquez-Abrams & nhahtdh Das beheben!
Zarkonnen
@Aerovistae re.match(r'1\n2', string)bedeutet re.match('1\\n2', string), wird also \nnicht von Python interpretiert, sondern vom Regex-Parser - es liefert tatsächlich das gleiche Ergebnis wie einfach, re.match('1\n2', string)da der Regex-Parser nicht entflohene Zeilenumbruchzeichen von Python gut verarbeitet (zumindest in meinen Python 3-Tests)
Aprillion
4

Sie scheinen mit der Idee zu kämpfen, dass ein RegEx nicht Teil von Python ist, sondern eine andere Programmiersprache mit einem eigenen Parser und Compiler. Raw - Strings Hilfe erhalten Sie die „Quellcode“ einen RegEx sicher zum RegEx - Parser, die Zeichenfolge wird dann assign Bedeutung wie \d, \w, \nusw ...

Das Problem besteht darin, dass Python und RegExps \als Escape-Zeichen verwendet werden, was übrigens ein Zufall ist. Es gibt Sprachen mit anderen Escape-Zeichen (wie "` n "für eine neue Zeile, aber selbst dort müssen Sie" \ n "verwenden. in RegExps). Der Vorteil ist, dass Sie in diesen Sprachen nicht zwischen rohen und nicht rohen Zeichenfolgen unterscheiden müssen. Beide versuchen nicht, den Text zu konvertieren und zu schlachten, da sie auf unterschiedliche Escape-Sequenzen reagieren.

Vladislav Zorov
quelle
1

Der entsprechende Abschnitt des Python-Handbuchs ("String- und Byte-Literale") enthält eine klare Erklärung der rohen String-Literale:

Sowohl Zeichenfolgen- als auch Byteliteralen können optional ein Buchstabe 'r' oder 'R' vorangestellt werden. Solche Zeichenfolgen werden als rohe Zeichenfolgen bezeichnet und behandeln Backslashes als wörtliche Zeichen. Infolgedessen werden in Zeichenfolgenliteralen '\ U' und '\ u' Escapezeichen in rohen Zeichenfolgen nicht speziell behandelt. Da sich die rohen Unicode-Literale von Python 2.x anders verhalten als die von Python 3.x, wird die 'ur'-Syntax nicht unterstützt.

Neu in Version 3.3: Das Präfix 'rb' von Rohbyte-Literalen wurde als Synonym für 'br' hinzugefügt.

Neu in Version 3.3: Die Unterstützung für das Unicode-Legacy-Literal (u'value ') wurde wieder eingeführt, um die Wartung der beiden Codebasen Python 2.x und 3.x zu vereinfachen. Weitere Informationen finden Sie in PEP 414.

In Zeichenfolgen mit dreifachen Anführungszeichen sind Zeilenumbrüche und Anführungszeichen ohne Leerzeichen zulässig (und werden beibehalten), mit der Ausnahme, dass drei Anführungszeichen ohne Leerzeichen in einer Zeile die Zeichenfolge beenden. (Ein "Anführungszeichen" ist das Zeichen, das zum Öffnen der Zeichenfolge verwendet wird, dh entweder "oder".)

Sofern kein Präfix 'r' oder 'R' vorhanden ist, werden Escape-Sequenzen in Zeichenfolgen nach Regeln interpretiert, die den von Standard C verwendeten ähnlich sind. Die erkannten Escape-Sequenzen sind:

Escape Sequence Bedeutung Hinweise

\ newline Backslash und newline ignoriert
\ Backslash ()
\ 'Einfaches Anführungszeichen (')
\ "doppeltes Anführungszeichen (")
\ a ASCII-Glocke (BEL)
\ b ASCII-Rücktaste (BS)
\ f ASCII-Formfeed (FF)
\ n ASCII-Zeilenvorschub (n ) LF)
\ r ASCII-Wagenrücklauf (CR)
\ t Horizontale Registerkarte ASCII (TAB) \ v Vertikale Registerkarte ASCII (VT)
\ ooo Zeichen mit Oktalwert ooo (1,3)
\ xhh Zeichen mit Hex-Wert hh (2,3)

Escape-Sequenzen, die nur in String-Literalen erkannt werden, sind:

Escape-Sequenz Bedeutung Hinweise \ N {Name} Name des Zeichennamens in der Unicode-Datenbank (4) \ uxxxx Zeichen mit 16-Bit-Hex-Wert xxxx (5) \ Uxxxxxxxx Zeichen mit 32-Bit-Hex-Wert xxxxxxxx (6)

Anmerkungen:

  1. Wie in Standard C werden bis zu drei Oktalstellen akzeptiert.

  2. Anders als in Standard C sind genau zwei hexadezimale Ziffern erforderlich.

  3. In einem Byte-Literal bezeichnen hexadezimale und oktale Escapezeichen das Byte mit dem angegebenen Wert. In einem String-Literal bezeichnen diese Escapezeichen ein Unicode-Zeichen mit dem angegebenen Wert.

  4. In Version 3.3 geändert: Unterstützung für Namensaliasnamen [1] wurde hinzugefügt.

  5. Mit dieser Escape-Sequenz können einzelne Codeeinheiten codiert werden, die Teile eines Ersatzpaares bilden. Es sind genau vier hexadezimale Ziffern erforderlich.

  6. Jedes Unicode-Zeichen kann auf diese Weise codiert werden. Zeichen außerhalb der BMP (Basic Multilingual Plane) werden jedoch mit einem Ersatzpaar codiert, wenn Python für die Verwendung von 16-Bit-Codeeinheiten kompiliert wird (Standardeinstellung). Es sind genau acht hexadezimale Ziffern erforderlich.

Im Gegensatz zu Standard C bleiben alle nicht erkannten Escape-Sequenzen in der Zeichenfolge unverändert, dh der Backslash bleibt in der Zeichenfolge. (Dieses Verhalten ist beim Debuggen hilfreich: Wenn eine Escape-Sequenz falsch eingegeben wird, wird die resultierende Ausgabe leichter als fehlerhaft erkannt.) Es ist auch wichtig zu beachten, dass die Escape-Sequenzen, die nur in Zeichenfolgenliteralen erkannt werden, in die Kategorie der nicht erkannten Escape-Zeichen für Bytes fallen Literale.

Selbst in einer rohen Zeichenfolge können Zeichenfolgenanführungszeichen mit einem Backslash maskiert werden, der Backslash bleibt jedoch in der Zeichenfolge. Beispielsweise ist r "" ein gültiges Zeichenfolgenliteral, das aus zwei Zeichen besteht: einem Backslash und einem doppelten Anführungszeichen; r "\" ist kein gültiges Zeichenfolgenliteral (selbst eine rohe Zeichenfolge kann nicht mit einer ungeraden Anzahl von Backslashes enden). Insbesondere kann eine rohe Zeichenfolge nicht mit einem einzelnen Backslash enden (da der Backslash dem folgenden Anführungszeichen entgehen würde). Beachten Sie auch, dass ein einzelner Backslash gefolgt von einer neuen Zeile als diese beiden Zeichen als Teil der Zeichenfolge und nicht als Zeilenfortsetzung interpretiert wird .

Lorenzo Gatti
quelle
0

\n ist eine Escape-Sequenz in Python

\w ist eine spezielle Sequenz in (Python) Regex

Sie sehen aus, als wären sie in derselben Familie, aber sie sind es nicht. Die Raw-String-Notation wirkt sich auf Escape-Sequenzen aus, nicht jedoch auf Regex-Spezialsequenzen.

Weitere Informationen zu Escape Sequences finden Sie unter "\ newline" unter https://docs.python.org/3/reference/lexical_analysis.html

Weitere Informationen zu speziellen Sequenzen: Suchen Sie nach "\ number" https://docs.python.org/3/library/re.html

deeproyalblue
quelle
0

Die Rohzeichenfolge wirkt sich nicht auf spezielle Sequenzen in Python-Regex wie \ w, \ d aus. Es betrifft nur Escape-Sequenzen wie \ n. Die meiste Zeit spielt es also keine Rolle, ob wir r vorne schreiben oder nicht.

Ich denke, das ist die Antwort, nach der die meisten Anfänger suchen.

Nick Ng
quelle