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%
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.
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?
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.
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
Damit bleibt vXcvv
übrig, damit die Engine zu
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
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
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
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:
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