Die Vorschläge in diesem Artikel konzentrieren sich hauptsächlich auf die Lesbarkeit regulärer Ausdrücke. Durch die Entwicklung dieser Gewohnheiten können Sie das Design und die Ausdrucksstruktur besser berücksichtigen, was dazu beiträgt, Fehler und Codewartung zu reduzieren sind selbst der Betreuer dieses Codes. Sie können selbst einen Blick darauf werfen und diese Erfahrungen mit regulären Ausdrücken in Ihrer tatsächlichen Anwendung berücksichtigen.
Reguläre Ausdrücke sind schwer zu schreiben, schwer zu lesen und schwer zu pflegen. Sie stimmen oft nicht mit unerwartetem Text überein oder lassen gültigen Text außer Acht. Diese Probleme werden durch die Leistung und Fähigkeiten regulärer Ausdrücke verursacht. Die Kombination von Fähigkeiten und Nuancen jedes Metazeichens macht es unmöglich, den Code zu interpretieren, ohne auf intellektuelle Tricks zurückzugreifen.
Viele Tools enthalten Funktionen, die das Lesen und Schreiben regulärer Ausdrücke erleichtern, sind aber auch sehr unidiomatisch. Für viele Programmierer ist das Schreiben regulärer Ausdrücke eine magische Kunst. Sie bleiben bei den Eigenschaften, die sie kennen, und haben eine Einstellung des absoluten Optimismus. Wenn Sie bereit sind, die fünf in diesem Artikel besprochenen Gewohnheiten zu übernehmen, können Sie reguläre Ausdrücke entwerfen, die Versuch und Irrtum standhalten.
In diesem Artikel werden die Sprachen Perl, PHP und Python als Codebeispiele verwendet. Die Ratschläge in diesem Artikel gelten jedoch für fast jede Implementierung von Ersatzausdrücken (Regex).
1.
Für die meisten Programmierer ist die Verwendung von Leerzeichen und Einrückungen in einer Umgebung mit regulären Ausdrücken kein Problem. Wenn sie dies nicht tun, werden sie von ihren Kollegen und sogar Laien mit Sicherheit ausgelacht. Fast jeder weiß, dass es schwierig ist, Code in einer Zeile zu lesen, zu schreiben und zu warten. Was ist der Unterschied für reguläre Ausdrücke?
Die meisten Tools zum Ersetzen von Ausdrücken verfügen über eine erweiterte Leerraumfunktion, die es Programmierern ermöglicht, ihre regulären Ausdrücke auf mehrere Zeilen zu erweitern und am Ende jeder Zeile Kommentare hinzuzufügen. Warum nutzen nur wenige Programmierer diese Funktion? Die regulären Ausdrücke von Perl 6 verwenden standardmäßig durch Leerzeichen erweiterte Muster. Lassen Sie nicht zu, dass die Sprache standardmäßig Leerzeichen für Sie erweitert, sondern nutzen Sie sie selbst.
Ein Trick, den Sie bei erweiterten Leerzeichen beachten sollten, besteht darin, die Engine für reguläre Ausdrücke anzuweisen, erweiterte Leerzeichen zu ignorieren. Wenn Sie also Leerzeichen abgleichen müssen, müssen Sie dies explizit angeben.
Fügen Sie in der Perl-Sprache x am Ende des regulären Ausdrucks hinzu, sodass „m/foo bar/“ die folgende Form annimmt:
m/
foo
Bar
/x
Fügen Sie in der PHP-Sprache x am Ende des regulären Ausdrucks hinzu, sodass „/foo bar/“ die folgende Form annimmt:
„/
foo
Bar
/x“
Übergeben Sie in der Python-Sprache den Musteränderungsparameter „re.VERBOSE“, um die kompilierte Funktion wie folgt zu erhalten:
Muster = r'''
foo
Bar
'''
regex = re.compile(pattern, re.VERBOSE)
komplexere reguläre Ausdrücke verarbeitet, werden Leerzeichen und Kommentare wichtiger. Angenommen, der folgende reguläre Ausdruck wird verwendet, um Telefonnummern in den Vereinigten Staaten abzugleichen:
(?d{3})? ?d{3}[-.]d{4}
Dieser reguläre Ausdruck entspricht Telefonnummern wie „( 314)555-4000“, glauben Sie, dass dieser reguläre Ausdruck mit „314-555-4000“ oder „555-4000“ übereinstimmt? Die Antwort ist, dass keines davon übereinstimmt. Das Schreiben einer solchen Codezeile verbirgt die Mängel und Designergebnisse selbst. Die Telefonvorwahl ist erforderlich, dem regulären Ausdruck fehlt jedoch ein Trennzeichen zwischen der Vorwahl und dem Präfix.
Wenn Sie diese Codezeile in mehrere Zeilen aufteilen und Kommentare hinzufügen, werden die Mängel aufgedeckt und die Änderung erleichtert.
In der Perl-Sprache sollte es die folgende Form haben:
/
(? # optionale Klammern
d{3} # Erforderliche Telefonvorwahl
)? # optionale Klammern
[-s.]? # Das Trennzeichen kann ein Bindestrich, ein Leerzeichen oder ein Punkt sein
d{3} # Dreistelliges Präfix
[-.] # Ein weiteres Trennzeichen
d{4} # Vierstellige Telefonnummer
/x
Der neu geschriebene reguläre Ausdruck verfügt jetzt über ein optionales Trennzeichen nach der Ortsvorwahl, sodass er mit „314-555-4000“ übereinstimmen sollte, die Ortsvorwahl ist jedoch weiterhin erforderlich. Ein anderer Programmierer, der die Telefonvorwahl optional machen muss, erkennt schnell, dass sie jetzt nicht optional ist, und eine kleine Änderung kann das Problem lösen.
2.
Beim Schreiben von Tests gibt es drei Teststufen. Jede Stufe erhöht die Zuverlässigkeit Ihres Codes. Zunächst müssen Sie sorgfältig darüber nachdenken, welche Codes abgeglichen werden müssen und ob Sie mit Nichtübereinstimmungen umgehen können. Zweitens müssen Sie Dateninstanzen verwenden, um den regulären Ausdruck zu testen. Abschließend müssen Sie ein Testgremium offiziell bestehen.
Bei der Entscheidung, was abgeglichen werden soll, geht es eigentlich darum, ein Gleichgewicht zwischen dem Abgleichen falscher Ergebnisse und dem Fehlen richtiger Ergebnisse zu finden. Wenn Ihre Regex zu streng ist, werden einige korrekte Übereinstimmungen fehlen; wenn sie zu locker ist, wird sie eine falsche Übereinstimmung erzeugen. Sobald ein regulärer Ausdruck in den eigentlichen Code übernommen wird, bemerken Sie möglicherweise nicht beides. Betrachten Sie das obige Telefonnummernbeispiel, das mit „800-555-4000 = -5355“ übereinstimmen würde. Tatsächlich sind falsche Übereinstimmungen schwer zu erkennen, daher ist es wichtig, im Voraus zu planen und sie gründlich zu testen.
Um mit dem Telefonnummernbeispiel fortzufahren: Wenn Sie eine Telefonnummer in einem Webformular bestätigen, können Sie mit einer zehnstelligen Nummer in jedem Format zufrieden sein. Wenn Sie jedoch Telefonnummern aus einer großen Textmenge trennen möchten, müssen Sie möglicherweise sorgfältig falsche Übereinstimmungen ausschließen, die die Anforderungen nicht erfüllen.
Wenn Sie über die Daten nachdenken, die Sie abgleichen möchten, schreiben Sie einige Fallszenarien auf. Schreiben Sie Code, um Ihren regulären Ausdruck anhand eines Case-Szenarios zu testen. Für jeden komplexen regulären Ausdruck ist es am besten, ein kleines Programm zum Testen zu schreiben, das die folgende spezifische Form annehmen kann.
In Perl-Sprache:
#!/usr/bin/perl
my @tests = ("314-555-4000",
„800-555-4400“,
„(314)555-4000“,
„314.555.4000“,
„555-4000“,
„aasdklfjklas“,
„1234-123-12345“
);
foreach mein $test (@tests) {
if ( $test =~ m/
(? # optionale Klammern
d{3} # Erforderliche Telefonvorwahl
)? # optionale Klammern
[-s.]? # Das Trennzeichen kann ein Bindestrich, ein Leerzeichen oder ein Punkt sein
d{3} # Dreistelliges Präfix
[-s.] # Ein weiteres Trennzeichen
d{4} # Vierstellige Telefonnummer
/X ) {
print „Übereinstimmung mit $testn“;
}
anders {
print „Fehler bei $testn“;
}
}
In PHP-Sprache:
<?php
$tests = array( "314-555-4000",
"800-555-4400",
„(314)555-4000“,
„314.555.4000“,
„555-4000“,
„aasdklfjklas“,
"1234-123-12345" );
$regex = "/
(? # optionale Klammern
d{3} # Erforderliche Telefonvorwahl
)? # optionale Klammern
[-s.]? # Das Trennzeichen kann ein Bindestrich, ein Leerzeichen oder ein Punkt sein
d{3} # Dreistelliges Präfix
[-s.] # Ein weiteres Trennzeichen
d{4} # Vierstellige Telefonnummer
/x";
foreach ($tests als $test) {
if (preg_match($regex, $test)) {
echo „Übereinstimmung mit $test
;";
}
anders {
echo „Abgleich bei $test fehlgeschlagen
;";
}
}
?>;
In Python-Sprache:
import re
tests = ["314-555-4000",
„800-555-4400“,
„(314)555-4000“,
„314.555.4000“,
„555-4000“,
„aasdklfjklas“,
„1234-123-12345“
]
Muster = r''''
(? # optionale Klammern
d{3} # Erforderliche Telefonvorwahl
)? # optionale Klammern
[-s.]? # Das Trennzeichen kann ein Bindestrich, ein Leerzeichen oder ein Punkt sein
d{3} # Dreistelliges Präfix
[-s.] # Ein weiteres Trennzeichen
d{4} # Vierstellige Telefonnummer
'''
regex = re.compile( Pattern, re.VERBOSE ) für Test in Tests:
wenn regex.match(test):
print „Matched on“, test, „n“
anders:
print „Failed match on“, test, „n“
Das Ausführen des Testcodes wird ein weiteres Problem offenbaren: Er stimmt mit „1234-123-12345“ überein.
Theoretisch müssen Sie alle Tests für die gesamte Anwendung in einem Testteam integrieren. Auch wenn Sie noch keine Testgruppe haben, sind Ihre regulären Ausdruckstests eine gute Grundlage dafür, und jetzt ist ein guter Zeitpunkt, damit zu beginnen. Auch wenn es noch nicht der richtige Zeitpunkt ist, ihn zu erstellen, sollten Sie den regulären Ausdruck dennoch nach jeder Änderung ausführen und testen. Wenn Sie hier ein wenig Zeit verbringen, ersparen Sie sich viel Ärger.
3. Gruppenwechselbetrieb
Das Wechselbetriebssymbol ( ) hat eine niedrige Priorität, was bedeutet, dass es oft öfter wechselt, als der Programmierer beabsichtigt hat. Der reguläre Ausdruck zum Extrahieren von E-Mail-Adressen aus Text könnte beispielsweise wie folgt lauten:
^CC: To:(.*)
Der obige Versuch ist falsch, aber dieser Fehler wird oft nicht bemerkt. Der Zweck des obigen Codes besteht darin, den Text zu finden, der mit „CC:“ oder „An:“ beginnt, und dann die E-Mail-Adresse am Ende dieser Zeile zu extrahieren.
Wenn „To:“ in der Mitte einer Zeile steht, erfasst dieser reguläre Ausdruck leider keine Zeile, die mit „CC:“ beginnt, sondern extrahiert stattdessen mehrere zufällige Textteile. Ehrlich gesagt stimmt der reguläre Ausdruck mit einer Zeile überein, die mit „CC:“ beginnt, erfasst aber nichts; oder er stimmt mit jeder Zeile überein, die „To:“ enthält, erfasst aber den Rest der Zeile. Normalerweise würde dieser reguläre Ausdruck eine große Anzahl von E-Mail-Adressen erfassen, sodass niemand den Fehler bemerken würde.
Wenn Sie die eigentliche Absicht erfüllen möchten, sollten Sie zur Verdeutlichung Klammern hinzufügen. Der reguläre Ausdruck lautet wie folgt:
(^CC:) (To:(.*))
Wenn die tatsächliche Absicht darin besteht, Text zu erfassen, der mit „ beginnt. Wenn Sie den Rest der Zeile mit „CC:“ oder „To:“ versehen, lautet der korrekte reguläre Ausdruck:
^(CC: To:)(.*)
Dies ist ein häufiger Fehler bei unvollständigen Übereinstimmungen, den Sie vermeiden, wenn Sie sich das Gruppieren zur Gewohnheit machen bei Wechselbetrieb Dieser Fehler.
4. Verwenden Sie lose Quantoren
wie „*?“, „+?“ und „??“, auch wenn diese das Schreiben und Verstehen des Ausdrucks erleichtern.
Entspannte Quantifizierer stimmen mit so wenig Text wie möglich überein, was zum Erfolg der exakten Übereinstimmung beiträgt. Wenn Sie „foo(.*?)bar“ schreiben würden, würde der Quantifizierer beim ersten Mal, wenn er auf „bar“ trifft, nicht mehr übereinstimmen, nicht beim letzten Mal. Dies ist wichtig, wenn Sie „###“ aus „foo###bar+++bar“ erfassen möchten. Ein strenger Quantor würde „###bar++ +“ erfassen. ;), das wird eine Menge Ärger verursachen. Wenn Sie gelockerte Quantifizierer verwenden, können Sie neue reguläre Ausdrücke generieren, indem Sie nur sehr wenig Zeit für die Zusammenstellung von Zeichentypen aufwenden.
Entspannte Quantoren sind von großem Wert, wenn Sie die Struktur des Kontexts kennen, in dem Sie den Text erfassen möchten.
5. Verwenden Sie verfügbare Trennzeichen.
In den Sprachen Perl und PHP wird häufig ein linker Schrägstrich (/) verwendet, um den Anfang und das Ende eines regulären Ausdrucks zu kennzeichnen. Wenn Sie in Perl und PHP auf der Verwendung von linken Schrägstrichen bestehen, sollten Sie Schrägstriche in Ausdrücken vermeiden. Wenn Sie in Python Anführungszeichen verwenden, sollten Sie Backslashes () vermeiden. Durch die Auswahl anderer Trennzeichen oder Anführungszeichen können Sie die Hälfte des regulären Ausdrucks vermeiden. Dadurch werden Ausdrücke leichter lesbar und mögliche Fehler, die durch das Vergessen der Vermeidung von Symbolen entstehen, werden reduziert.
Die Sprachen Perl und PHP erlauben die Verwendung aller nicht numerischen Zeichen und Leerzeichen als Trennzeichen. Wenn Sie zu einem neuen Trennzeichen wechseln, können Sie vermeiden, dass beim Abgleich von URLs oder HTML-Tags (z. B. „http://“ oder „<br/>;“) der linke Schrägstrich fehlt.
Beispielsweise kann „/http://(S)*/“ als „#http://(S)*#“ geschrieben werden.
Gängige Trennzeichen sind „#“, „!“ und „“. Wenn Sie eckige Klammern, spitze Klammern oder geschweifte Klammern verwenden, passen Sie diese einfach an. Hier sind einige Beispiele für gängige Trennzeichen:
#…# !…! {…} s … … (nur Perl) s[…][…] (nur Perl) s<…>;/…/ (nur Perl)
In Python wird ein regulärer Ausdruck zunächst als String behandelt. Wenn Sie Anführungszeichen als Trennzeichen verwenden, entgehen Ihnen alle Backslashes. Sie können dieses Problem jedoch vermeiden, indem Sie die Zeichenfolge „r“ verwenden. Wenn Sie für die Option „re.VERBOSE“ drei aufeinanderfolgende einfache Anführungszeichen verwenden, können Sie Zeilenumbrüche einfügen. Beispielsweise kann regex = "( file://w+)(//d +)" in der folgenden Form geschrieben werden:
regex = r'''
(w+)
(d+)
'''