Hinweis: Nachdem ich das selbst ausprobiert hatte, wurde mir schnell klar, was für ein Fehler das war. Deshalb ändere ich die Regeln ein wenig.
Die minimal erforderliche Funktionalität:
- Charakterklassen (
.
,\w
,\W
, etc.) - Multipliers (
+
,*
, und?
) - Einfache Erfassungsgruppen
Ihre Herausforderung besteht darin, PCRE in der Sprache Ihrer Wahl unter den folgenden Bedingungen zu implementieren :
- Sie dürfen die systemeigenen RegEx-Funktionen Ihrer Sprache in keiner Weise verwenden . Sie dürfen auch keine RegEx-Bibliothek eines Drittanbieters verwenden.
- Ihr Eintrag sollte so viel von der PCRE-Spezifikation implementieren. wie möglich.
Ihr Programm sollte als Eingabe 2 Zeilen akzeptieren:
- der reguläre Ausdruck
- die Zeichenfolge, mit der verglichen werden soll
Ihr Programm sollte in seiner Ausgabe Folgendes angeben:
- Stimmt die RegEx mit der Eingabezeichenfolge überein?
- Die Ergebnisse aller Erfassungsgruppen
Der Gewinner ist der Beitrag, der einen Großteil der Spezifikation implementiert. wie möglich. Im Falle eines Gleichstands ist der Gewinner nach meiner Einschätzung der kreativste Beitrag.
Bearbeiten: um ein paar Dinge zu klären, sind hier einige Beispiele für Eingaben und erwartete Ausgaben:
- Eingang:
^ \ s * (\ w +) $ Hallo
- Ausgabe:
Übereinstimmungen: ja Gruppe 1: "Hallo"
- Eingang:
(\ w +) @ (\ w +) (?: \. com | \ .net) [email protected]
- Ausgabe:
Übereinstimmungen: ja Gruppe 1: 'sam' Gruppe 2: "Test"
code-challenge
regular-expression
Nathan Osman
quelle
quelle
Antworten:
Python
Da die Implementierung von vollständigem PCRE zu viel ist, habe ich nur eine wesentliche Teilmenge davon implementiert.
Unterstützt
|.\.\w\W\s+*()
. Der reguläre Ausdruck muss korrekt sein.Beispiele:
Wie es funktioniert:
Eine detaillierte Theorie finden Sie in dieser Einführung in Automatentheorie, Sprachen und Berechnung .
Die Idee ist, den ursprünglichen regulären Ausdruck in nichtdeterministische endliche Automaten (NFA) umzuwandeln. Tatsächlich sind reguläre PCRE-Ausdrücke zumindest kontextfreie Grammatiken, für die wir Pushdown-Automaten benötigen, aber wir beschränken uns auf eine Teilmenge von PCRE.
Endliche Automaten sind gerichtete Graphen, in denen Knoten Zustände sind, Kanten Übergänge sind und jeder Übergang eine passende Eingabe hat. Zunächst starten Sie von einem vordefinierten Startknoten. Wann immer Sie eine Eingabe erhalten, die einem der Übergänge entspricht, nehmen Sie diesen Übergang in einen neuen Zustand. Wenn Sie einen Endknoten erreicht haben, wird dies als Eingabe bezeichnet, die von Automaten akzeptiert wurde. In unserem Fall ist die Eingabe eine Matching-Funktion, die true zurückgibt.
Sie werden als nichtdeterministische Automaten bezeichnet, da es manchmal mehr übereinstimmende Übergänge gibt, die Sie aus demselben Zustand ableiten können. In meiner Implementierung müssen alle Übergänge in denselben Zustand mit demselben übereinstimmen, daher habe ich die Übereinstimmungsfunktion zusammen mit dem Zielzustand (
states[dest][0]
) gespeichert .Wir wandeln unseren regulären Ausdruck mit Hilfe von Bausteinen in endliche Automaten um. Ein Building Block hat einen Startknoten (
first
) und einen Endknoten (last
) und stimmt mit etwas aus dem Text überein (mögliche leere Zeichenfolge).Die einfachsten Beispiele sind
True
(first == last
)c == txt[pos]
(first == last
)(
first == last`)Sie benötigen auch die neue Position im Text, an der das nächste Token gefunden werden soll.
Kompliziertere Beispiele sind (Großbuchstaben stehen für Blöcke).
passendes B +:
passend zu A | B | C:
Alle Regexp-Operatoren können auf diese Weise transformiert werden. Probieren Sie es einfach aus
*
.Der letzte Teil ist das Parsen des regulären Ausdrucks, der eine sehr einfache Grammatik erfordert:
Hoffentlich ist die Implementierung einer einfachen Grammatik (ich denke, sie ist LL (1), aber korrigieren Sie mich, wenn ich falsch liege) viel einfacher als die Erstellung einer NFA.
Sobald Sie die NFA haben, müssen Sie zurückverfolgen, bis Sie den Endknoten erreichen.
Quellcode (oder hier ):
quelle
(a+b)+
entsprichtabaabaaabaaaab
.