Ich möchte eine Erläuterung des Verhaltens von Perls Engine für reguläre Ausdrücke erhalten

8

Aktualisierung von @Borodin

Ich habe diesen Code als etwas umgeschrieben, von dem ich glaube, dass es verständlicher ist. Das OP hat b mit d und ähnlichem verglichen, und ich habe alle Symbole in deutlichere ASCII-Zeichen geändert. Das Ergebnis entspricht dem ursprünglichen Code des OPs

Ich habe alle Regex-Muster kurz manuell überprüft, aber ich sehe keine Diskrepanz

%Vor%

Ausgabe

%Vor%


Das folgende Perl-Programm testet einige Strings gegen verschiedene Regex-Muster, die Rückverweise verwenden. Es veranschaulicht ein Verhalten, das ich nicht verstehen kann.

Die Variablen $snum und $rnum werden nur verwendet, um die Zeichenfolgen und Muster in der Ausgabe zu nummerieren, um das Lesen zu erleichtern. Liest nur den Inhalt des @test -Arrays.

%Vor%

Ausgabe

%Vor%

Beachten Sie, dass egrep (oder jedenfalls GNU egrep ) denkt, dass jeder obige Test eine Übereinstimmung ist.

Ich denke, das ist die theoretisch "richtige" Antwort, wenn regexp disjunction als eine nicht-deterministische Wahl interpretiert wird, in dem Sinne, dass es eine Auswahl von Alternativen gibt, die die Übereinstimmung zum Erfolg führen.

Beachten Sie auch, dass ( S2 , S3 , R1 ) durch Ersetzen von b für d überall in ( S0 , S1 , R0 ) erhalten wird, was ein weiterer Grund ist zu denken, dass der vierte Test ein Match sein sollte.

Intuitiv möchte ich auch, dass die Tests 4-7 Übereinstimmungen sind, insofern die Tests 0-3 sind.

Ich kann irgendwie verstehen, wie man beim vierten Test nicht zusammenpassen würde: indem man den linken Zweig und den rechten rechten Zweig in dieser Reihenfolge an jeder Disjunktion ausprobiert, wenn backtracking nicht korrekt wiederherstellt Variable auf ihren vorherigen Wert, erkundet der linke Zweig der R1-Disjunktion auf dem letzten ab Teilstring von S3 clobber zu a , was dann nicht zu seinem aa -Wert zurückverfolgt werden würde, wodurch die Übereinstimmung fehlschlägt (Das Gleiche würde in keinem der vorherigen Tests passieren).

Aber ich habe keine Ahnung, ob meine Analyse richtig ist. Warum der fünfte Test nicht passt, entgeht mir wirklich.

Wie auch immer, meine Frage ist eine Kombination aus den folgenden:

  • Kann jemand Perls Regexp-Engine-Verhalten an diesen Beispielen im Detail erklären?

  • Ist dieses Verhalten beabsichtigt? Ist das irgendwo dokumentiert?

  • Soll ich einen Fehler einreichen?

Gro-Tsen 22.05.2016, 15:25
quelle

3 Antworten

2

Es gibt ein noch einfacheres Beispiel für den Unterschied zwischen egrep und Perl:

%Vor%

Interessanterweise sind die folgenden Übereinstimmungen in Perl (und auch in egrep):

%Vor%

Also wird die erste a mit der ersten Iteration von * abgeglichen, b wird mit der zweiten verglichen (weil eq 'b' ). Zur gleichen Zeit eq 'a' , aber eq 'A' . Warum ist eq 'a' ? Es scheint ein Ergebnis der vorherigen Iteration von * zu sein, was ich als Fehler bezeichnen würde.

Update: Ich habe einen Fehler gemeldet.

    
choroba 22.05.2016 21:06
quelle
1

Lassen Sie uns das vierte Beispiel ausprobieren. (Bitte nummeriere sie nicht von Null! Ich Leute, nicht Computer!)

%Vor%

stimmt nicht mit

überein %Vor%
  • Am Anfang der Zeichenfolge stimmt Perl mit der ersten der beiden Alternativen überein. vvX stimmt mit (v*) X überein, so dass Sie die Alternative nicht ausprobieren müssen. Dadurch wird auch Capture 2 als vv

    gespeichert

    Damit bleibt vXcvv übrig, damit die Engine zu

    passt
  • Auch hier verwendet Perl vX , um mit (v*) X übereinzustimmen. Es speichert Capture 2 als v und die Engine wird für einen weiteren Versuch verwendet

    Das lässt cvv

    übrig
  • Die einzigen Optionen, die übrig bleiben, sind eine weitere Iteration von ( (v*) X | H? (v*) X )* , oder sie fallen aus dieser Schleife in c

  • Der Text beginnt nicht mit v , X oder H , damit die Schleife endet, und die nächste Übereinstimmung ist c , und die Regex-Engine stimmt mit c

    überein

    Jetzt gibt es nur noch vv

  • Perl sucht nun nach einer Übereinstimmung, um 2 zu erfassen, was v ist. Das gelingt

    Die verbleibende Zeichenfolge ist nur v

  • Jetzt sucht Perl nach $ , was das Ende einer Zeichenkette oder kurz vor einer neuen Zeile am Ende einer Zeichenkette ist. Es sieht v und es schlägt fehl

Ich hoffe wirklich, dass das hilft. Ich habe es nicht eilig, die verbleibenden vier Beispiele zu erklären, und ich kann noch nicht verstehen, warum es Verwirrung gibt.

Ich habe nicht mit egrep experimentiert, und ich bin überrascht, dass es sich anders verhält. Vielleicht stapelt es die Captures nicht wie Perl?

Bitte lassen Sie mich wissen, ob es noch etwas Interessantes gibt

    
Borodin 22.05.2016 17:44
quelle
0

So verstehe ich das Verhalten:

%Vor%

Der erste Teil der Alternative schlägt hier fehl, dann verwenden wir den zweiten Teil.

Die Gruppe 2 enthält a , also verwendet die Rückreferenz die Regex wie folgt:

%Vor%

Das stimmt nicht mit der Zeichenfolge aababcaa überein, die am Ende aa hat.

Die Übereinstimmung ist in Ordnung, wenn du eine doppelte aa in der Mitte hast: aabaabcaa

    
Toto 22.05.2016 16:40
quelle

Tags und Links