Regex: Zeichenfolgen schnell und effizient überprüfen
Sie beginnen mit dem Schreiben von Skripten und Programmen und merken, dass Sie immer wieder auf ähnliche Aufgaben stoßen. Statt umständliche Konstruktionen aus Schleifen und Abfragen zu bauen, empfehle ich: Regex!
In diesem Blog will ich Ihnen näher bringen, was Regex konkret kann und wofür wir es verwenden. Meine Beispiele zeigen: Es ist gar nicht so kompliziert, wie es scheint.
Was ist Regex?
In der allgemeinen Informatik ist eine Regular Expression (abgekürzt als Regex oder RegExp) ein regulärer Ausdruck. Also eine Zeichenfolge, mit der eine Reihe von Zeichenfolgen mithilfe einiger Syntaxregeln beschrieben wird. Diese sind vor allem in der Softwareentwicklung und im Webdesign in Verwendung. Regex ist zum Beispiel bei Anwendungen wichtig, die Eingaben des Benutzers erwarten. Das ist etwa bei bei Online-Formularen der Fall.
Wofür Sie eine Regular Expression brauchen.
Ein Regex kann Ihnen den Alltag als Programmierer und Softwareentwickler gleich mehrfach erleichtern.
- Formate überprüfen: Mit dem regulären Ausdruck wird die Richtigkeit eines Formats oder einer Syntax geprüft.
- Texte durchsuchen: Hilft bei der Zerlegung von Texten nach bestimmten Regeln. Regex setzt etwa spezifische Filter ein, so können Texte einfacher nach Keywords durchsucht werden.
- Eingaben untersuchen: Regex überprüft die Webformulare nach gültigen Eingaben des Benutzers.
- Einheitliche Sprache: Alle Beteiligten arbeiten mit denselben Ausdrücken, was die Kommunikation vereinfacht.
Wichtig zu wissen:
Es gibt mehrere Arten für die Regular Expression Syntax:
PCRE
steht für Perl Compatible Regular Expressions und wird hauptsächlich in Programmiersprachen wie JS, PHP, C,... verwendet.
POSIX
wird unter Unixoide Betriebssystemen verwendet (Shell und Programme).
In den meisten Programmen werden die Extended Regular Expressions (ERE) verwendet und in einzelnen ausnahmen (z.B. sed oder grep) die etwas älteren Basic Regular Expressions (BRE).
Der Unterschied zwischen Basic und Extended Regular Expressions besteht darin dass Sonderzeichen (?, +, (), {}, und |) sich anders Verhalten.
Bei der Basic Regular Expressions muss ein “\” vor einem Zeichen gesetzt sein damit es als Sonderzeichen interpretiert wird.
Bei Extended Regular Expressions ist es umgekehrt, diese Zeichen sind Sonderzeichen.
Zum Beispiel beim Programm grep sorgt die Option -E, dass nun Extended Regular Expression verwendet wird.
Welche Herausforderungen sind mit dem Einsatz regulärer Ausdrücke verbunden?
Wenn man mit Anweisungen für reguläre Ausdrücke arbeiten möchte, hat man viel Freiheit, da es für jede Aufgabe, die mit einem regulären Ausdruck gelöst werden soll, immer mehrere Lösungsoptionen gibt.
Es ist jedoch nicht immer von Vorteil, dass ein gewünschtes Ergebnis auf unterschiedliche Weise erzielt wird: Beispielsweise können die allgemeinen Anweisungen für ein Ergebnis zu restriktiv sein. Eine Übersicht über die Länge kann ich ebenfalls empfehlen. Je kompakter ein regulärer Ausdruck ist, desto kürzer ist seine Verarbeitungszeit.
Wie funktioniert ein Regulärer Ausdruck?
Optional kann ein regulärer Ausdruck nur mit normalen Zeichen (abc) oder einer Kombination aus normalen Zeichen und Metazeichen (ab * c) gebildet werden. Das sind Metazeichen: [ ] ( ) { } | ? + - * . ^ $ \
Metazeichen haben die Aufgabe, bestimmte Konstruktionen oder Anordnungen von Zeichen zu beschreiben, wie etwa ob ein Zeichen am Anfang der Zeile stehen soll oder ob ein Zeichen genau einmal, keinmal, öfter oder seltener vorkommen kann.
Die Regex-Grundregeln
Ich habe für Sie einige Regex-Grundregeln zusammengefasst, die mich im Alltag unterstützen.
Zeichen | Erklärung |
[abc] | Mit den eckigen Klammern [ und ] wird eine Zeichenauswahl definiert. Das Beispiel findet eines dieser Zeichen. |
[a-e] | Ein Bindestrich definiert einen bestimmten Bereich. Das Beispiel findet die Zeichen a, b, c, d und e. Auch hier muss nur eines der Zeichen zutreffen. |
[a-zA-Z0-9] | Innerhalb einer Zeichenauswahl können auch mehrere Gruppen und Einzelzeichen stehen. Im Beispiel entspricht die Zeichenauswahl den Kleinbuchstaben a bis z, den Großbuchstaben A bis Z und sowie den Ziffern 0 bis 9. |
[0-9] | Der Bindestrich lässt sich auch nur auf Zahlen anwenden. Das Beispiel steht für die Ziffern 0 bis 9 |
[^a] | Durch das ^ Zeichen am Anfang einer Zeichenauswahl wird diese negiert. Das bedeutet, dass es jedes Zeichen finden würde bis auf das nach dem ^. |
^a | Steht dieses Zeichen nicht innerhalb einer Klammer, so bedeutet es, dass es für den Anfang eines Textes steht. |
a$ | Dieses Zeichen steht für das Ende einer Zeile oder einer Zeichenkette. |
. | Der Punkt steht für ein beliebiges Zeichen und kann somit jedes Zeichen finden. |
a* | Das Zeichen vor dem Stern darf beliebig oft vorkommen. |
.* | Punkt und Stern in Kombination findet X-beliebig viele Zeichen. |
a+ | Das Zeichen vor dem + muss mindestens einmal vorkommen. |
ab{2} | Die Buchstaben die davor stehen, müssen exakt 2 Mal gefunden werden. |
ab? | Das Fragezeichen bedeutet, dass das Zeichen vorkommen kann aber es muss nicht vorkommen. |
(a|A) | Die Pipe | agiert als ODER. Es darf nur eines der beiden Zeichen(-ketten) vorkommen. |
$1 | Ist die Rückwärtsreferenz auf eine Gruppe bzw. ein Teilmuster. Vor allem für das Suchen und Ersetzen wichtig. $1 bezieht sich auf die erste Klammer- Gruppe. |
Verwendung von vordefinierten Zeichenklassen.
Es gibt aber auch noch vordefinierte Zeichenklassen. Sie machen die regulären Ausdrücke kürzer und einfacher.
\d | Dieser Ausdruck steht für eine Ziffer (Digit), ist also gleichbedeutend mit [0-9]. |
\D | Dieser Ausdruck steht für ein Zeichen, das keine Ziffer ist. Es entspräche also [^0-9] oder [^\d]. |
\w | Dieser Ausdruck (Word) steht für einen Buchstaben, eine Ziffer oder einen Unterstrich [a-zA-Z0-9_] |
\W | Entspricht einem Zeichen, das kein Buchstabe, keine Ziffer und kein Unterstrich ist. |
\s | Dieser Ausdruck steht für Whitespace , also Leerzeichen und Tabs. |
\S | Dieser Ausdruck steht für alle Zeichen, die kein Whitespace sind, also für [^s]. |
[] | Ein Paar eckiger Klammern kennzeichnet eine Zeichenklasse, die immer für ein einziges Zeichen in einem Suchmuster steht. |
() | Ein Paar runder Klammern kennzeichnet eine Zeichengruppe, die aus einem oder mehreren Zeichen bestehen und ineinander geschaltet werden können. |
| | Kennzeichnet zwei oder mehrere Alternativen |
? | Zeichen, Klasse oder Gruppe vor einem Fragezeichen ist optional und darf maximal einmal vorkommen. |
\. | Das Backslash schütz ein Zeichen vor der Metafunktion. Findet das Zeichen Punkt und nicht ein beliebiges Zeichen wie es die Metafunktion vorsieht. |
Ein komplexeres Beispiel: Validierung von E-Mail-Adressen
Die Validierung einer eingegebenen E-Mail-Adresse erfordert einen komplexeren Ausdruck. Im Formular wird die Eingabe type=email verwendet, aber im Hintergrund findet die Prüfung mit einem Regulären Ausdruck statt. Wie hier zum Beispiel:
[A-Za-z0-9\-\_\.\+]{1,64}@[A-Za-z0-9\-\_\.]+\.[a-zA-Z]+
Der Ausdruck vor dem @-Zeichen definiert die erlaubten Zeichen und die maximale Zeichenlänge für den verwendeten Namen. Nach dem @-Zeichen definiert es die erlaubten Zeichen.
Tipps:
Sie können hier nachsehen wie komplexe Regex-ketten für z.b. MAC oder IPv6 Adressen aufgebaut sind. Die Regex-Ketten können aber auch als Unterstützung in der Programmierung dienen:
https://github.com/hpcugent/logstash-patterns/blob/master/files/grok-patterns
Unter https://regexr.com/ kannst du deine Regular Expressions testen, zudem kannst du hier zwischen PCRE und POSIX Regular Expression umschalten.
Rückwärtsreferenz auf eine Gruppe
Du kannst in manchen Programmiersprachen (Java, PHP) oder auch in Programmen wie der Webserver Nginx einen regulären Ausdruck erstellen, und Teile die Übereinstimmen als Platzhalter zwischenspeichern.
Beispiel:
Regular Expression: MeinString(.*)Bei(spiel)
Hier wäre die Rückwärtsreferenz $1 alles was zwischen MeinString stehen würde und bei und $2 “spiel”.
Weitere Beispiele:
Unix Pfad: (/([\w_%!$@:.,~-]+|\\.)*)+
Windows Pfad: (?>[A-Za-z]+:|\\)(?:\\[^\\?*]*)+
Hexadezimal: (?<![0-9A-Fa-f])(?:[+-]?(?:0x)?(?:[0-9A-Fa-f]+))
Quoted String: (?>(?<!\\)(?>"(?>\\.|[^\\"]+)+"|""|(?>'(?>\\.|[^\\']+)+')|''|(?>`(?>\\.|[^\\`]+)+`)|``))
Mein Fazit
Reguläre Ausdrücke scheinen am Anfang recht kompliziert zu sein. Wenn man sich damit auseinandersetzt wird einem klar, wie schnell ganze Zeichenketten überprüft werden können. Und auch wenn ein regulärer Ausdruck je nach Anforderung sehr komplex werden kann, ist Regex für mich immer eine super Unterstützung in der Softwareentwicklung.