Viele Programmierer kennen die Freude, einen schnellen regulären Ausdruck zu erstellen, heutzutage oft mit Hilfe eines Webdienstes oder traditionellerweise bei interaktiver Eingabeaufforderung, oder vielleicht ein kleines Skript zu schreiben, das den regulären Ausdruck in der Entwicklung hat, und eine Sammlung von Testfällen . In beiden Fällen ist der Vorgang iterativ und ziemlich schnell: Hacken Sie so lange an der kryptisch aussehenden Zeichenfolge, bis sie Ihren Wünschen entspricht und sie erfasst und ablehnt, was Sie nicht möchten.
Für einen einfachen Fall könnte das Ergebnis wie folgt aussehen:
Pattern re = Pattern.compile(
"^\\s*(?:(?:([\\d]+)\\s*:\\s*)?(?:([\\d]+)\\s*:\\s*))?([\\d]+)(?:\\s*[.,]\\s*([0-9]+))?\\s*$"
);
Viele Programmierer wissen auch, wie schwierig es ist, einen regulären Ausdruck zu bearbeiten oder nur einen regulären Ausdruck in einer alten Codebasis zu codieren. Mit ein wenig Bearbeitung, um es aufzuteilen, ist es für jeden, der mit Regexps einigermaßen vertraut ist, immer noch sehr einfach, es über Regexp zu verstehen, und ein Regexp-Veteran sollte sofort sehen, was es tut (antworten Sie am Ende des Beitrags, falls jemand die Übung haben möchte es selbst herauszufinden).
Es muss jedoch nicht viel komplexer werden, damit ein regulärer Ausdruck wirklich nur zum Schreiben verwendet werden kann, und selbst bei sorgfältiger Dokumentation (die natürlich jeder für alle komplexen regulären Ausdrücke ausführt, die er schreibt ...) wird das Ändern der regulären Ausdrücke zu einem Problem entmutigende Aufgabe. Es kann auch eine sehr gefährliche Aufgabe sein, wenn reguläre Ausdrücke nicht sorgfältig auf Einheit getestet werden (aber jeder hat natürlich umfassende Komponententests für all seine komplexen regulären Ausdrücke, sowohl positiv als auch negativ ...).
Also, um es kurz zu machen, gibt es eine Schreib-Lese-Lösung / Alternative für reguläre Ausdrücke, ohne ihre Macht zu verlieren? Wie würde der obige reguläre Ausdruck mit einem alternativen Ansatz aussehen? Jede Sprache ist in Ordnung, obwohl eine mehrsprachige Lösung am besten wäre, sind reguläre Ausdrücke mehrsprachig.
Und dann ist das, was der frühere reguläre Ausdruck tut: parsen Sie eine Zeichenfolge von Zahlen im Format 1:2:3.4
, erfassen Sie jede Zahl, wo Leerzeichen erlaubt sind und nur 3
erforderlich sind.
Antworten:
Einige Leute haben erwähnt, aus kleineren Teilen zu komponieren, aber noch hat niemand ein Beispiel geliefert.
Nicht am besten lesbar, aber ich glaube, es ist klarer als das Original.
Auch hat C # , um den
@
Operator, der in einen String , um vorangestellt werden kann , um anzuzeigen , dass es wörtlich genommen werden soll (kein Escape - Zeichen), sonumber
wäre@"([\d]+)";
quelle
[\\d]+
und[0-9]+
gerade sein sollte\\d+
(na ja, können einige finden[0-9]+
mehr lesbar). Ich werde die Frage nicht bearbeiten, aber Sie können diese Antwort korrigieren.\d
sie stimmen mit allem überein, was als Zahl angesehen wird, auch mit anderen Nummerierungssystemen (Chinesisch, Arabisch usw.), während[0-9]
sie nur mit den Standardziffern übereinstimmen. Ich habe es jedoch standardisiert\\d
und in dasoptionalDecimal
Muster einbezogen.Der Schlüssel zur Dokumentation des regulären Ausdrucks ist die Dokumentation. Viel zu oft werfen die Leute Leitungsgeräusche hinein und belassen es dabei.
Innerhalb von Perl
/x
unterdrückt der Operator am Ende des regulären Ausdrucks Leerzeichen, sodass der reguläre Ausdruck dokumentiert werden kann.Der obige reguläre Ausdruck würde dann lauten:
Ja, es ist ein bisschen aufwendig mit vertikalen Leerzeichen, obwohl man es verkürzen könnte, ohne zu viel Lesbarkeit zu opfern.
Wenn man sich diesen regulären Ausdruck ansieht, kann man sehen, wie es funktioniert (und was nicht). In diesem Fall stimmt dieser reguläre Ausdruck mit der Zeichenfolge überein
1
.Ähnliche Ansätze können in einer anderen Sprache gewählt werden. Die Option python re.VERBOSE funktioniert dort.
Perl6 (das obige Beispiel war für Perl5) führt dies mit dem Konzept der Regeln weiter, das zu noch leistungsfähigeren Strukturen führt als das PCRE (es bietet Zugriff auf andere Grammatiken (kontextfrei und kontextsensitiv) als nur reguläre und erweiterte reguläre).
In Java (wo dieses Beispiel herkommt) kann man Zeichenkettenverkettung verwenden, um den regulären Ausdruck zu bilden.
Zugegebenermaßen führt dies zu viel mehr
"
Verwirrung in der Zeichenfolge, kann leichter gelesen (insbesondere mit Syntaxhervorhebung bei den meisten IDEs) und dokumentiert werden.Der Schlüssel liegt darin, die Kraft zu erkennen und einmal zu schreiben, in die reguläre Ausdrücke häufig fallen. Das Schreiben des Codes, um dies defensiv zu vermeiden, damit der reguläre Ausdruck klar und verständlich bleibt, ist der Schlüssel. Wir formatieren Java-Code aus Gründen der Klarheit - reguläre Ausdrücke unterscheiden sich nicht, wenn die Sprache Ihnen die Möglichkeit dazu bietet.
quelle
Der "ausführliche" Modus, der von einigen Sprachen und Bibliotheken angeboten wird, ist eine der Antworten auf diese Bedenken. In diesem Modus wird das Leerzeichen in der Regexp-Zeichenfolge entfernt (Sie müssen es also verwenden
\s
), und Kommentare sind möglich. Hier ist ein kurzes Beispiel in Python, das dies standardmäßig unterstützt:In jeder Sprache, in der dies nicht der Fall ist, sollte die Implementierung eines Übersetzers vom ausführlichen in den "normalen" Modus eine einfache Aufgabe sein. Wenn Sie sich Sorgen über die Lesbarkeit Ihrer regulären Ausdrücke machen, würden Sie diese Zeitinvestition wahrscheinlich ziemlich leicht rechtfertigen.
quelle
In jeder Sprache, in der reguläre Ausdrücke verwendet werden, können Sie sie aus einfacheren Blöcken zusammensetzen, um das Lesen zu vereinfachen. Bei allem, was komplizierter als Ihr Beispiel ist, sollten Sie diese Option auf jeden Fall nutzen. Das besondere Problem mit Java und vielen anderen Sprachen ist, dass sie reguläre Ausdrücke nicht als "erstklassige" Bürger behandeln, sondern dass sie sich über String-Literale in die Sprache einschleichen müssen. Dies bedeutet, dass viele Anführungszeichen und umgekehrte Schrägstriche nicht Teil der Regex-Syntax sind und die Lesbarkeit beeinträchtigen. Außerdem können Sie nicht viel besser lesbar werden, ohne Ihre eigene Minisprache und Ihren eigenen Interpreter zu definieren.
Der prototypisch bessere Weg, reguläre Ausdrücke zu integrieren, war natürlich Perl mit seiner Whitespace-Option und den Regex-Anführungszeichen-Operatoren. Perl 6 erweitert das Konzept des Aufbaus von regulären Ausdrücken von Teilen zu rekursiven Grammatiken, was in der Anwendung so viel besser ist, als es wirklich überhaupt nicht zu vergleichen. Die Sprache mag das Boot der Aktualität verfehlt haben, aber ihre reguläre Unterstützung war The Good Stuff (tm).
quelle
Ich verwende gerne Expresso: http://www.ultrapico.com/Expresso.htm
Diese kostenlose Anwendung hat die folgenden Funktionen, die ich im Laufe der Zeit nützlich finde:
Mit dem soeben eingereichten regulären Ausdruck würde dies beispielsweise so aussehen:
Natürlich ist es tausend Worte wert, es zu versuchen, es zu beschreiben. Bitte beachten Sie auch, dass ich in irgendeiner Weise mit dem Editor dieser Anwendung verwandt bin.
quelle
Für einige Dinge kann es hilfreich sein, nur eine Grammatik wie BNF zu verwenden. Diese können viel einfacher zu lesen sein als reguläre Ausdrücke. Ein Tool wie GoldParser Builder kann dann die Grammatik in einen Parser umwandeln, der das schwere Heben für Sie erledigt.
Die Grammatiken BNF, EBNF usw. können viel einfacher zu lesen und zu erstellen sein als komplizierte reguläre Ausdrücke. GOLD ist ein Werkzeug für solche Dinge.
Der unten stehende c2-Wiki-Link enthält eine Liste möglicher Alternativen, die gegoogelt werden können, einschließlich einiger Diskussionen darüber. Es ist im Grunde ein "Siehe auch" -Link, um meine Grammatik-Engine-Empfehlung zu vervollständigen:
Alternativen zu regulären Ausdrücken
quelle
Dies ist eine alte Frage und ich habe keine Erwähnung von verbalen Ausdrücken gesehen, daher dachte ich, ich würde diese Informationen auch für zukünftige Suchende hier hinzufügen. Verbale Ausdrücke wurden speziell entwickelt, um Regex für den Menschen verständlich zu machen, ohne die symbolische Bedeutung von Regex erlernen zu müssen. Siehe folgendes Beispiel. Ich denke, das macht das Beste, wonach Sie fragen.
Dieses Beispiel ist für Javascript. Sie können diese Bibliothek jetzt für viele Programmiersprachen finden.
quelle
Der einfachste Weg wäre, immer noch Regex zu verwenden, aber Ihren Ausdruck aus einfacheren Ausdrücken mit beschreibenden Namen zu erstellen, z. B. http://www.martinfowler.com/bliki/ComposedRegex.html (und ja, das ist von string concat).
Alternativ können Sie auch eine Parser-Kombinator-Bibliothek verwenden, z. B. http://jparsec.codehaus.org/ , mit der Sie einen vollständig rekursiven anständigen Parser erhalten. Auch hier kommt die wahre Kraft aus der Komposition (diesmal aus der funktionalen Komposition).
quelle
Ich dachte, es wäre wert, Logstashs Grok- Ausdrücke zu erwähnen . Grok baut auf der Idee auf, lange Parsing-Ausdrücke aus kürzeren zusammenzusetzen. Es ermöglicht das bequeme Testen dieser Bausteine und ist mit über 100 häufig verwendeten Mustern vorverpackt . Abgesehen von diesen Mustern können alle regulären Ausdrücke verwendet werden.
Das oben in grok ausgedrückte Muster ist (ich habe es in der Debugger-App getestet, aber es könnte fehlerhaft sein):
Die optionalen Teile und Leerzeichen lassen es etwas hässlicher erscheinen als sonst, aber sowohl hier als auch in anderen Fällen kann die Verwendung von grok das Leben schöner machen.
quelle
In F # haben Sie das Modul FsVerbalExpressions . Es erlaubt Ihnen, Regexes aus verbalen Ausdrücken zusammenzustellen, es hat auch einige vorgefertigte Regexes (wie URL).
Eines der Beispiele für diese Syntax lautet wie folgt:
Wenn Sie mit der F # -Syntax nicht vertraut sind, ist groupName die Zeichenfolge "GroupNumber".
Dann erstellen sie einen verbalen Ausdruck (VerbEx), den sie als "COD (? <GroupNumber> [0-9] {3}) END" konstruieren. Was sie dann an der Zeichenkette "COD123END" testen, wo sie die benannte Erfassungsgruppe "GroupNumber" erhalten. Dies ergibt 123.
Ich finde die normale Regex ehrlich gesagt viel einfacher zu verstehen.
quelle
Verstehe zunächst, dass Code, der nur funktioniert, schlechter Code ist. Guter Code muss auch alle aufgetretenen Fehler genau melden.
Wenn Sie beispielsweise eine Funktion schreiben, mit der Bargeld von einem Benutzerkonto auf ein anderes Benutzerkonto übertragen wird. Sie würden nicht einfach einen "bearbeiteten oder fehlgeschlagenen" Booleschen Wert zurückgeben, da dies dem Anrufer keine Vorstellung davon gibt, was schief gelaufen ist, und es dem Anrufer nicht ermöglicht, den Benutzer ordnungsgemäß zu informieren. Stattdessen haben Sie möglicherweise eine Reihe von Fehlercodes (oder eine Reihe von Ausnahmen): Zielkonto nicht gefunden, nicht genügend Guthaben im Quellkonto, Berechtigung verweigert, keine Verbindung zur Datenbank möglich, zu viel Last (später erneut versuchen) usw .
Denken Sie nun an das Beispiel "Analysieren einer Zahlenfolge im Format 1: 2: 3.4". Alles, was der Regex tut, ist das Melden eines "Bestanden / Nicht Bestanden", bei dem dem Benutzer kein angemessenes Feedback angezeigt werden kann (unabhängig davon, ob es sich um eine Fehlermeldung in einem Protokoll oder eine interaktive Benutzeroberfläche handelt, in der die Fehler rot als angezeigt werden) Benutzertypen oder was auch immer). Welche Arten von Fehlern werden nicht richtig beschrieben? Falsches Zeichen in der ersten Nummer, erste Nummer zu groß, fehlender Doppelpunkt nach der ersten Nummer usw.
Um "schlechten Code, der nur funktioniert" in "guten Code, der ausreichend beschreibende Fehler liefert" umzuwandeln, müssen Sie den regulären Ausdruck in viele kleinere reguläre Ausdrücke aufteilen (normalerweise sind reguläre Ausdrücke so klein, dass es einfacher ist, sie ohne reguläre Ausdrücke auszuführen) ).
Das Lesen / Warten des Codes ist nur eine zufällige Folge des Erhalts des Codes.
quelle
:
? Stellen Sie sich einen Compiler vor, der nur eine Fehlermeldung ("ERROR") hatte, die zu dumm war, um den Benutzer über das Problem zu informieren. Stellen Sie sich jetzt Tausende von Websites vor, die genauso dumm sind und (z. B.) "Schlechte E-Mail-Adresse" und nichts mehr anzeigen.