Der reguläre Ausdruck, den Sie zitieren, ist ein schreckliches Durcheinander, und ich glaube nicht, dass irgendjemand zustimmt, dass er lesbar ist. Gleichzeitig hängt ein Großteil dieser Hässlichkeit mit dem zu lösenden Problem zusammen: Es gibt mehrere Ebenen der Verschachtelung und die URL-Grammatik ist relativ kompliziert (sicherlich zu kompliziert, um in jeder Sprache prägnant zu kommunizieren). Es ist jedoch sicher richtig, dass es bessere Möglichkeiten gibt, um zu beschreiben, was dieser reguläre Ausdruck beschreibt. Warum werden sie nicht verwendet?
Ein großer Grund ist Trägheit und Allgegenwart. Es erklärt nicht, warum sie so populär wurden, aber jetzt, da sie es sind, kann jeder, der reguläre Ausdrücke kennt, diese Fähigkeiten (mit sehr wenigen Unterschieden zwischen Dialekten) in hundert verschiedenen Sprachen und tausend zusätzlichen Softwaretools anwenden ( zB Texteditoren und Kommandozeilen-Tools). Letztere würden und könnten übrigens keine Lösung verwenden, die dem Schreiben von Programmen gleichkommt , da sie von Nicht-Programmierern häufig verwendet werden.
Trotzdem werden reguläre Ausdrücke häufig überbeansprucht, das heißt, auch wenn ein anderes Tool viel besser wäre. Ich halte die Regex-Syntax nicht für schrecklich . Aber bei kurzen und einfachen Mustern ist es deutlich besser: Das archetypische Beispiel für Bezeichner in C-ähnlichen Sprachen [a-zA-Z_][a-zA-Z0-9_]*
kann mit einem absoluten Minimum an Regex-Kenntnissen gelesen werden, und sobald dieser Balken erreicht ist, ist es sowohl offensichtlich als auch gut prägnant. Es ist nicht von Natur aus schlecht, weniger Zeichen zu benötigen, ganz im Gegenteil. Prägnanz ist eine Tugend, sofern Sie nachvollziehbar bleiben.
Es gibt mindestens zwei Gründe, warum sich diese Syntax bei einfachen Mustern wie diesen auszeichnet: Die meisten Zeichen müssen nicht mit einem Escapezeichen versehen werden, daher wird sie relativ natürlich gelesen, und es werden alle verfügbaren Interpunktionszeichen verwendet, um eine Vielzahl einfacher Parsing-Kombinatoren auszudrücken. Vielleicht am wichtigsten ist , erfordert es keine alles überhaupt für die Sequenzierung. Sie schreiben das erste, dann das, was danach kommt. Vergleichen Sie dies mit Ihrem followedBy
, insbesondere wenn das folgende Muster kein wörtlicher, sondern ein komplizierterer Ausdruck ist.
Warum scheitern sie in komplizierteren Fällen? Ich sehe drei Hauptprobleme:
Es gibt keine Abstraktionsmöglichkeiten. Formale Grammatiken, die aus demselben Gebiet der theoretischen Informatik stammen wie Regexes, haben eine Reihe von Produktionen, so dass sie Zwischenteilen des Musters Namen geben können:
# This is not equivalent to the regex in the question
# It's just a mock-up of what a grammar could look like
url ::= protocol? '/'? '/'? '/'? (domain_part '.')+ tld
protocol ::= letter+ ':'
...
Wie wir oben sehen konnten, ist ein Leerzeichen ohne besondere Bedeutung nützlich, um eine augenschonende Formatierung zu ermöglichen. Gleiches gilt für Kommentare. Reguläre Ausdrücke können das nicht, weil ein Leerzeichen genau das ist, ein Literal ' '
. Beachten Sie jedoch, dass einige Implementierungen einen "ausführlichen" Modus zulassen, in dem Leerzeichen ignoriert und Kommentare möglich sind.
Es gibt keine Metasprache, um gängige Muster und Kombinatoren zu beschreiben. Zum Beispiel kann man eine digit
Regel einmal schreiben und in einer kontextfreien Grammatik weiterverwenden, aber man kann nicht sozusagen eine "Funktion" definieren, die einer Produktion gegeben ist p
und eine neue Produktion erzeugt, die etwas Besonderes damit macht, zum Beispiel erstellen eine Produktion für eine kommagetrennte Liste von Vorkommen von p
.
Der von Ihnen vorgeschlagene Ansatz löst diese Probleme mit Sicherheit. Es löst sie einfach nicht sehr gut, weil es weitaus prägnanter handelt als nötig. Die ersten beiden Probleme können gelöst werden, während eine relativ einfache und knappe domänenspezifische Sprache verwendet wird. Das dritte, na ja ... eine programmatische Lösung erfordert natürlich eine universelle Programmiersprache, aber meiner Erfahrung nach ist das dritte bei weitem das geringste dieser Probleme. Nur wenige Muster haben genug Vorkommen für dieselbe komplexe Aufgabe, nach der sich der Programmierer nach der Möglichkeit sehnt, neue Kombinatoren zu definieren. Und wenn dies notwendig ist, ist die Sprache oft so kompliziert, dass sie ohnehin nicht mit regulären Ausdrücken analysiert werden kann und sollte.
Für diese Fälle gibt es Lösungen. Es gibt ungefähr zehntausend Parser-Combinator-Bibliotheken, die in etwa das tun, was Sie vorschlagen, nur mit einer anderen Menge von Operationen, häufig einer anderen Syntax und fast immer mit mehr Parsing-Power als reguläre Ausdrücke (dh sie befassen sich mit kontextfreien Sprachen oder einigen beträchtlichen Sprachen) Teilmenge davon). Dann gibt es Parser-Generatoren, die mit dem oben beschriebenen Ansatz "Verwenden Sie ein besseres DSL" gehen. Und es gibt immer die Möglichkeit, einen Teil des Parsings von Hand in richtigen Code zu schreiben. Sie können sogar mischen und abgleichen, indem Sie reguläre Ausdrücke für einfache Unteraufgaben verwenden und die komplizierten Dinge im Code ausführen, die die regulären Ausdrücke aufrufen.
Ich weiß nicht genug über die frühen Jahre des Rechnens, um zu erklären, wie reguläre Ausdrücke so populär wurden. Aber sie sind hier, um zu bleiben. Sie müssen sie nur mit Bedacht einsetzen und nicht , wenn das klüger ist.