Die maßgebliche Referenz zu den pragmatischen Aspekten der Implementierung von Regex-Engines ist eine Reihe von drei Blog-Posts von Russ Cox . Wie dort beschrieben, werden Rückverweise mithilfe von Backtracking implementiert, da Ihre Sprache durch Rückverweise unregelmäßig wird .
Lookaheads und Lookbehinds passen wie viele Features von Regex-Pattern-Matching-Engines nicht ganz in das Paradigma, zu entscheiden, ob ein String Mitglied einer Sprache ist oder nicht. Bei regulären Ausdrücken suchen wir normalerweise nach Teilzeichenfolgen in einer größeren Zeichenfolge. Die "Übereinstimmungen" sind Teilzeichenfolgen, die Mitglieder der Sprache sind, und der Rückgabewert ist der Anfangs- und Endpunkt der Teilzeichenfolge in der größeren Zeichenfolge.
Der Punkt von Lookaheads und Lookbehinds besteht weniger darin, die Fähigkeit einzuführen, nicht reguläre Sprachen abzugleichen, sondern vielmehr die Position anzupassen, an der die Engine den Anfangs- und Endpunkt der übereinstimmenden Teilzeichenfolge meldet.
Ich verlasse mich auf die Beschreibung unter http://www.regular-expressions.info/lookaround.html . Die Regex-Engines, die diese Funktion unterstützen (Perl, TCL, Python, Ruby, ...), scheinen alle auf Backtracking zu basieren (dh sie unterstützen einen viel größeren Satz von Sprachen als nur die regulären Sprachen). Sie scheinen diese Funktion als eine relativ "einfache" Erweiterung des Backtracking zu implementieren, anstatt zu versuchen, echte endliche Automaten zu konstruieren, um die Aufgabe auszuführen.
Positiver Lookahead
Die Syntax für den positiven Lookahead ist (?=
Regex)
. So q(?=u)
stimmt zum Beispiel q
nur überein , wenn es gefolgt wird u
, aber nicht mit dem übereinstimmt u
. Ich stelle mir vor, sie implementieren dies mit einer Variation des Backtrackings. Erstellen Sie eine FSM für den Ausdruck vor dem positiven Lookahead. Wenn diese Übereinstimmungen gefunden wurden, merken Sie sich, wo sie geendet haben, und starten Sie eine neue FSM, die den Ausdruck im positiven Lookahead darstellt. Wenn dies zutrifft, haben Sie eine "Übereinstimmung", aber die Übereinstimmung "endet" kurz vor der Position, an der die positive Vorausschau-Übereinstimmung begonnen hat.
Das Einzige, was ohne Backtracking schwierig wäre, ist, dass Sie sich an den Punkt in der Eingabe erinnern müssen, an dem der Lookahead beginnt, und Ihr Eingabeband an diese Position zurückschieben, nachdem Sie mit dem Match fertig sind.
Negativer Lookahead
Die Syntax für den negativen Lookahead ist (?!
Regex)
. So q(?!u)
passt zum Beispiel q
nur, wenn es nicht gefolgt wird u
. Dies kann entweder ein q
gefolgt von einem anderen Zeichen oder ein Zeichen q
ganz am Ende der Zeichenfolge sein. Ich stelle mir vor, dass dies implementiert wird, indem eine NFA für den Lookahead-Ausdruck erstellt wird, die dann nur erfolgreich ist, wenn die NFA nicht mit der nachfolgenden Zeichenfolge übereinstimmt.
Wenn Sie dies tun möchten, ohne sich auf das Zurückverfolgen zu verlassen, können Sie die NFA des Lookahead-Ausdrucks negieren. Behandeln Sie sie dann genauso, wie Sie den positiven Lookahead behandeln.
Positiver Lookbehind
(?<=
)
(?=q)u
u
q
q
nnn
Sie könnten in der Lage sein , dies , indem der Schnittpunkt von „Zeichenfolge, die Enden mit ohne Rückzieher zu implementieren regex “ mit dem, was Teil der Regex , die vor dem Bediener kommt Lookbehind. Dies wird jedoch schwierig, da der Lookbehind- Regex möglicherweise weiter zurückschauen muss als der aktuelle Anfang der Eingabe.
Negativer Lookbehind
Die Syntax für negative Lookbehind ist (?<!
Regex)
. So zum Beispiel (?<!q)u
Streichhölzer u
, aber nur, wenn es nicht vorangestellt ist q
. Also würde es mit dem u
In umbrella
und dem u
In übereinstimmen doubt
, aber nicht mit dem u
In quick
. Wiederum scheint dies durch Berechnen der Länge von Regex , Sichern dieser Anzahl von Zeichen, Testen der Übereinstimmung mit Regex zu geschehen , wobei nun jedoch die gesamte Übereinstimmung fehlschlägt, wenn der Lookbehind übereinstimmt.
Möglicherweise können Sie dies ohne Zurückverfolgung implementieren, indem Sie die Negation von Regex verwenden und dann dasselbe tun, wie Sie es für einen positiven Lookbehind tun würden.