Wann sollten Sie keine regulären Ausdrücke verwenden? [geschlossen]

50

Reguläre Ausdrücke sind ein mächtiges Werkzeug im Arsenal von Programmierern, aber - es gibt Fälle, in denen sie nicht die beste Wahl sind oder sogar geradezu schädlich.

Einfaches Beispiel # 1 analysiert HTML mit Regexp - ein bekannter Weg zu zahlreichen Fehlern. Wahrscheinlich ist dies auch auf das Parsen im Allgemeinen zurückzuführen.

Aber gibt es noch andere Bereiche, in denen reguläre Ausdrücke eindeutig verboten sind?


ps: " Die Frage, die Sie stellen, erscheint subjektiv und wird wahrscheinlich geschlossen. " - Ich möchte daher betonen, dass ich an Beispielen interessiert bin, bei denen die Verwendung von regulären Ausdrücken bekanntermaßen Probleme verursacht.

c69
quelle
9
Das Parsen von HTML mit regulären Ausdrücken ist nicht nur "ein bekannter Weg zu zahlreichen Fehlern". Es ist eigentlich unmöglich .
Kramii setzt Monica
19
Es ist nicht nur unmöglich, es führt auch zu Wahnsinn und ewiger Verdammnis
Martin Wickman
3
@ Jörg: Regexp ist nur eine Abkürzung für regulären Ausdruck.
Joren
3
@ Jörg: Es ist sehr richtig, dass es einen massiven Unterschied zwischen regulären Ausdrücken in der Mathematik und ihren Implementierungen in Softwarebibliotheken gibt. Es ist auch richtig, dass die meisten Bibliotheken für reguläre Ausdrücke Erweiterungen haben, mit denen sie nicht nur reguläre Sprachen akzeptieren, und dass es nicht immer angemessen ist, sie als reguläre Ausdrücke zu bezeichnen. Ich stimme Ihnen zu, dass es zwei verschiedene Konzepte gibt. Aber sie haben den gleichen Namen; regexp ist immer noch nur eine Abkürzung, kein Begriff für sich. Viele dieser Beispiele auf dieser Website verwenden den vollständigen Begriff für die Softwarebibliotheken.
Joren
2
@ Jörg - das ist Semantik. Während es eine gute Idee sein mag, diese Muster in verschiedenen Namen zu bezeichnen (wenn nur der Irrtum "reguläre Ausdrücke sind für reguläre Sprachen" vermieden werden soll), ist "regexp" / "reguläre Ausdrücke" kein sehr guter Versuch und führt nur zu zusätzliche Verwirrung.
Kobi

Antworten:

60

Verwenden Sie keine regulären Ausdrücke:

  • Wenn es Parser gibt.

Dies ist nicht auf HTML beschränkt . Ein einfaches gültiges XML kann nicht mit einem regulären Ausdruck analysiert werden, selbst wenn Sie das Schema kennen und wissen, dass es sich niemals ändern wird.

Versuchen Sie beispielsweise nicht, C # -Quellcode zu analysieren . Analysieren Sie es stattdessen, um eine aussagekräftige Baumstruktur oder die Token zu erhalten.

  • Ganz allgemein, wenn Sie bessere Werkzeuge für Ihre Arbeit haben.

Was ist, wenn Sie nach einem Buchstaben suchen müssen, der sowohl klein als auch groß ist? Wenn Sie reguläre Ausdrücke lieben, werden Sie sie verwenden. Aber ist es nicht einfacher / schneller / lesbarer, zwei Suchen nacheinander durchzuführen? Wahrscheinlich erzielen Sie in den meisten Sprachen eine bessere Leistung und verbessern die Lesbarkeit Ihres Codes.

Zum Beispiel ist der Beispielcode in Ingos Antwort ein gutes Beispiel, wenn Sie keine regulären Ausdrücke verwenden müssen. Einfach suchen foo, dann nach bar.

  • Beim Parsen von menschlichem Schreiben.

Ein gutes Beispiel ist ein Obszönitätsfilter. Es ist nicht nur eine schlechte Idee , es zu implementieren, sondern Sie könnten auch versucht sein, es mit regulären Ausdrücken zu tun, und Sie werden es falsch machen. Es gibt viele Möglichkeiten, wie ein Mensch ein Wort, eine Zahl oder einen Satz schreiben kann und von einem anderen Menschen verstanden wird, aber nicht von Ihrem regulären Ausdruck. Anstatt also echte Obszönität zu empfinden, verbringt Ihr regulärer Ausdruck Ihre Zeit damit, andere Benutzer zu verletzen.

  • Bei der Validierung einiger Datentypen.

Überprüfen Sie beispielsweise eine E-Mail-Adresse nicht mit einem regulären Ausdruck. In den meisten Fällen werden Sie es falsch machen. In seltenen Fällen werden Sie es richtig machen und mit einem 6 343 Zeichen langen Codierungshorror abschließen .

Ohne die richtigen Werkzeuge werden Sie Fehler machen. Und Sie werden sie im letzten Moment bemerken, oder vielleicht nie. Wenn Sie sich nicht für sauberen Code interessieren, schreiben Sie eine Zeichenfolge mit zwanzig Zeilen ohne Kommentare, ohne Leerzeichen und ohne Zeilenumbrüche.

  • Wann wird Ihr Code gelesen? Und dann immer wieder und immer wieder von verschiedenen Entwicklern gelesen.

Im Ernst, wenn ich Ihren Code nehme und ihn überprüfen oder ändern muss, möchte ich nicht eine Woche lang versuchen, eine zwanzig Zeilen lange Zeichenfolge mit vielen Symbolen zu verstehen.

Arseni Mourzenko
quelle
9
"Im Ernst, wenn ich Ihren Code nehme und ihn überprüfen oder ändern muss, möchte ich nicht eine Woche lang versuchen, eine zwanzig Zeilen lange Zeichenkette mit vielen Symbolen zu verstehen." +1!
Funkybro
1
Dies ist eine viel bessere Antwort als seine Stiefschwester beim Stack Overflow: stackoverflow.com/questions/7553722/…
Kobi
1
Wenn Sie Perl / PCRE verwenden (und wahrscheinlich auch die anderen modernen Regex- (?(DEFINE))Varianten), informieren Sie sich über Subroutinen, benannte Erfassungsgruppen und Behauptungen sehr ähnlich zu dem, was Sie in yacc oder ähnlich schreiben würden;)
NikiC
2
Die Verwendung regulärer Ausdrücke zum Wegschneiden von Wörtern auf der schwarzen Liste ist ein klarer Fehler.
Dan Ray
Es gibt keinen Grund auf der Welt, eine Regex nicht auf eine Saite wie diese zu werfen "<a href='foo'>stuff</a>". Moderne Regexes haben damit keine Probleme.
Tchrist
18

Das Wichtigste: Wenn die Sprache, die Sie analysieren, keine reguläre Sprache ist .

HTML ist keine reguläre Sprache und das Parsen mit einem regulären Ausdruck ist nicht möglich (nicht nur schwierig oder ein Weg zum fehlerhaften Code).

Matteo
quelle
4
Falsch! Wenn Sie eine der modernen Regex-Varianten (Perl, PCRE, Java, .NET, ...) verwenden, können Sie Rekursionen und Behauptungen erstellen und damit auch kontextfreie und kontextsensitive Grammatiken analysieren.
NikiC
9
@NikiC. Nicht falsch. "Moderne Regex-Aromen" sind keine regulären Ausdrücke (die zum Parsen regulärer Sprachen verwendet werden können, daher der Name). Ich bin damit einverstanden, dass Sie mit PRE mehr tun können, aber ich würde sie nicht einfach "reguläre Ausdrücke" nennen (wie in der ursprünglichen Frage).
Matteo
1
Moderne reguläre Ausdrücke gehen so weit über das hinaus, was Ihrer Oma beigebracht wurde, dass reguläre Ausdrücke dies tun könnten, wenn ihr Rat unerheblich ist. Und selbst einfache reguläre Ausdrücke können mit den meisten kleinen HTML-Ausschnitten umgehen. Dieses generelle Verbot ist lächerlich und unrealistisch. Reguläre Ausdrücke wurden gemacht für diese Art der Sache. Und ja, ich weiß wovon ich spreche .
Tchrist
12

Beim Stapelüberlauf werden häufig reguläre Ausdrücke abgefragt, die herausfinden, ob ein bestimmter String dieses oder jenes nicht enthält. Dies ist meiner Meinung nach eine Umkehrung des Zwecks des regulären Ausdrucks. Selbst wenn es eine Lösung gibt (unter Verwendung negativer Lookbehind-Behauptungen oder dergleichen), ist es oftmals viel besser, die Regex für das zu verwenden, wofür sie erstellt wurde, und den negativen Fall mit Programmlogik zu behandeln.

Beispiel:

# bad
if (/complicated regex that assures the string does NOT conatin foo|bar/) {
    # do something
}

# appropriate
if (/foo|bar/) {
    # error handling
} else {
    # do something
}
Ingo
quelle
1
+1: Ich habe es ein paar Mal vermieden, mich mit Regex in eine Ecke zu treiben, indem ich angehalten habe und mich gefragt habe: "Okay, was versuche ich konkret zusammenzupassen?" anstatt "Was versuche ich zu vermeiden?"
5

Zwei Fälle:

Wenn es einfacher geht

  • Die meisten Sprachen bieten eine einfache Funktion wie INSTR, um festzustellen, ob eine Zeichenfolge eine Teilmenge einer anderen ist. Wenn Sie dies möchten, verwenden Sie die einfachere Funktion. Schreiben Sie nicht Ihren eigenen regulären Ausdruck.

  • Wenn eine Bibliothek zur Durchführung einer komplexen Zeichenfolgenmanipulation verfügbar ist, verwenden Sie diese, anstatt Ihren eigenen regulären Ausdruck zu schreiben.

Wenn reguläre Ausdrücke nicht mächtig genug sind

  • Wenn Sie einen Parser benötigen, verwenden Sie einen Parser.
Kramii setzt Monica wieder ein
quelle
0

Reguläre Ausdrücke können keine rekursiven Strukturen identifizieren . Dies ist die grundlegende Einschränkung.

Nehmen wir JSON - es ist ein ziemlich einfaches Format, aber da ein Objekt andere Objekte als Elementwerte enthalten kann (willkürlich tief), ist die Syntax rekursiv und kann nicht von einem regulären Ausdruck analysiert werden. Andererseits kann CSV von regulären Ausdrücken analysiert werden, da es keine rekursiven Strukturen enthält.

Kurz gesagt, reguläre Ausdrücke lassen nicht zu, dass sich das Muster auf sich selbst bezieht. Sie können nicht sagen: An dieser Stelle in der Syntax stimmen Sie wieder mit dem gesamten Muster überein. Um es anders auszudrücken, reguläre Ausdrücke stimmen nur linear überein. Sie enthalten keinen Stapel, der es ermöglicht, zu verfolgen, wie tief ein verschachteltes Muster ist.

Beachten Sie, dass es nichts damit zu tun hat, wie komplex oder verworren das Format ansonsten ist. S-Ausdrücke sind wirklich sehr einfach, können aber nicht mit einem regulären Ausdruck analysiert werden. CSS2 hingegen ist eine recht komplexe Sprache, enthält jedoch keine rekursiven Strukturen und kann daher mit einem regulären Ausdruck analysiert werden. (Dies gilt jedoch nicht für CSS3, da CSS-Ausdrücke eine rekursive Syntax haben.)

Das liegt also nicht daran, dass es hässlich oder komplex oder fehleranfällig ist, HTML nur mit regulären Ausdrücken zu analysieren. Es ist einfach nicht möglich .

Wenn Sie ein Format analysieren müssen, das rekursive Strukturen enthält, müssen Sie die Verwendung regulärer Ausdrücke mindestens durch einen Stapel ergänzen, um die Ebene rekursiver Strukturen zu verfolgen. So funktioniert normalerweise ein Parser. Reguläre Ausdrücke werden verwendet, um die "linearen" Teile zu erkennen, während benutzerdefinierter Code außerhalb des regulären Ausdrucks verwendet wird, um die verschachtelten Strukturen zu verfolgen.

Normalerweise wird das Parsen so in separate Phasen aufgeteilt. Tokenisierung ist die erste Phase, in der reguläre Ausdrücke verwendet werden, um die Eingabe in eine Folge von "Token" wie Wörter, Interpunktion, Klammern usw. zu unterteilen. Parsing ist die nächste Phase, in der diese Token in eine hierarchische Struktur, einen Syntaxbaum, zerlegt werden.

Wenn Sie also hören, dass HTML oder C # nicht mit regulären Ausdrücken analysiert werden können, beachten Sie, dass reguläre Ausdrücke immer noch ein kritischer Bestandteil der Parser sind. Sie können eine solche Sprache nur mit regulären Ausdrücken und ohne Hilfscode analysieren .

JacquesB
quelle