Warum produzieren diese beiden Python-Regexe unterschiedliche Ergebnisse?

>>> re.match(r'"([^"]|(\\\"))*"', r'"I do not know what \"A\" is"').group(0) '"I do not know what \\"' >>> re.match(r'"((\\\")|[^"])*"', r'"I do not know what \"A\" is"').group(0) '"I do not know what \\"A\\" is"' 

Diese beiden Regexen sollen nach zitierten Strings suchen, mit Escaped-Zitat-Sequenzen. Der Unterschied, wenn ich nicht etwas fehlt, ist die Reihenfolge der Disjunktion in den Klammern.

Warum nehmen sie nicht beide die ganze Saite an?

3 Solutions collect form web for “Warum produzieren diese beiden Python-Regexe unterschiedliche Ergebnisse?”

Die Reihenfolge in Wechselgruppen ist wichtig.

In der ersten Regex wird die [^"] Alternative zuerst für jedes Zeichen versucht, es passt jedes einzelne Zeichen bis zu (und einschließlich) dem ersten \ . Beim nächsten Zeichen ( " ) fällt diese Alternative ( [^"] ) und die Andere ( \\\" ) versucht. Letzteres scheitert auch, da "A nicht mit \\\" übereinstimmt. Dies stoppt den Quantifizierer * von weiteren Spielen.

In der zweiten Regex ist die \\\" Alternative (Klammer ist redundant) zuerst für jedes Zeichen versucht und scheitert, so dass die zweite Alternative ( [^"] ) übereinstimmt. Aber bei den ersten \ die ersten alternativen Streichhölzer geht der Lookup-Pointer vorbei an \" A und der Lookup geht weiter.

Als eine allgemeine Faustregel, legen Sie den schmalsten Ausdruck im Wechsel zuerst.

Was du sagst, ist wahr, die Ordnung ist anders. Und noch etwas anderes ist anders.
Die erste "([^"]|(\\\"))*" wird mit einer Flucht übereinstimmen
Match "asdf\" sde ", während die andere nicht.

Auch wenn du mit Escape-Zitat umgehen musst, musst du auch Escapes behandeln. Also ist keines gültig.

Hier sind zwei Arten von Standard-Möglichkeiten, dies zu tun.
Beide behandeln die Flucht.
Sie können dies auch auf einfache Anführungszeichen erweitern.
Benutze den Dot-All-Modifikator (?s) wenn du Newlines überspannen möchtest.

Methode 1. – Wechsel

"(?:\\.|[^"\\]+)*"

  " (?: \\ . # Escape anything | # or, [^"\\]+ # Not escape not quote )* " 

Methode 2. – abgerollte Schleife

"[^"\\]*(?:\\.[^"\\]*)*"

  " [^"\\]* # Optional not escape not quote (?: \\ . # Escape anything [^"\\]* # Optional not escape not quote )* " 

Beide machen das gleiche. Methode 2 ist drei bis fünf Mal schneller als Methode 1.

Die Regex r'(A|B)' wird zuerst versuchen, mit A übereinzustimmen, und nur wenn das scheitert, wird es versuchen, B ( docs )

So wird die Regex ([^"]|(\\\") zuerst versuchen, mit einem Nicht-Anführungszeichen übereinzustimmen, und wenn das scheitert, wird es versuchen, mit einem Escaped-Anführungszeichen übereinzustimmen.

Wenn also der Regex \"A\" erreicht, stimmt der erste Teil Teil mit dem \ (es handelt sich nicht um ein Zitat, aber dann kein Teil passt, so dass das Spiel endet. Der Backslash wird von der [^"] verschoben, also der zweite Die Hälfte des Ausdrucks wird nie benutzt.

(\\ ") | [^"]), wenn es \"A\" wird zuerst versuchen, die \" (es funktioniert) dann wird es versuchen, A (es entspricht [^"] und So geht das Spiel weiter.

  • Python Regex - Ersetzen Sie einen String nicht zwischen zwei spezifischen Wörtern
  • Hashtable / Wörterbuch / Kartensuche mit regulären Ausdrücken
  • Regex - passend zu einem Charakter und all seinen diakritischen Variationen (aka akzentunempfindlich)
  • Regulärer Ausdruck, um das Wort zu passen, aber nicht das Wort in anderen Saiten
  • Regex Frage über Parsing Methode Signatur
  • Wie verwende ich eine Dezimalzahl in einem Django URL Pattern?
  • Regex funktioniert gut auf Pythex, aber nicht in Python
  • Python's re-Modul - sparender Zustand?
  • Wie macht man Sed wie Text mit Python ersetzen?
  • Parsing GPS-Empfänger Ausgabe über Regex in Python
  • Python Regex suchen
  • Python ist die beste Programmiersprache der Welt.