I know regular expressions!
Datum: Oktober 2020
Lesedauer: 6 Minuten
Quelle: https://content.codecademy.com/courses/regex/regular_expressions_xkcd_2.png (opens in a new tab)
Regex?
Stell dir vor, du bestellst online ein Produkt. Bevor du bezahlen kannst, musst du dich Registrieren. Es werden folgende Angaben von dir verlangt:
- E-Mail-Adresse
- Benutzername
- Passwort
Dabei werden deine Eingaben validiert. Doch wie wird dies gemacht?
Es gibt eine Technologie, die fast auf jeder Webseite präsent ist: Regex
Eine Regex, auch "regular expression" genannt, ist eine Abfolge von Zeichen, die ein Suchmuster definiert. Mit diesem Suchmuster können dann die passenden Strings gefunden werden.
Regex ermöglicht folgendes:
- Eine Eingabe eines Nutzers im Formular validieren
- Texte überprüfen
- Resultate auswerten
- Wörter in Mails oder auf Webseiten suchen
Regex ist in vielen Tools und Sprachen integriert:
- Unix
- Java, Python, PHP, …
- Entwicklungsumgebungen und Text Editoren
Anwendung
Wie oben beschrieben, kann man Regex zu verschiedenen Dingen einsetzen. Hier zeige ich dies anhand von Beispielen. Dabei werden die Übereinstimmungen im Text jeweils hervorgehoben
angezeigt.
Wörtlich
Es kann nach einem spezifischem String gesucht werden.
Apple
Apple
Google
Samsung
Alternativ
Es kommt vor, dass man nach mehreren Wörtern sucht. Dabei kann man mehrere Abfragen mit "|" (oder) verknüpfen. Im Beispiel sucht man nach baseball oder football.
baseball|football
baseball
football
rugby
Gruppen von Zeichen
Diese regular expression wird oft verwendet, um Wörter mit verschiedenen Schreibweisen zu finden. Diese Ergebnisse können später vereinheitlicht werden.
Ka[iy]
Kai
Kay
Kao
Kau
Hinweis
[kay]
stimmt nicht mit "kay" überein, sondern nur die einzelnen Zeichen stimmen.
Punkte
Manchmal weiss man, dass eine Zahl vorkommt.
Tim hat . Tore geschossen
Tim hat 3 Tore geschossen
Tim hat keine Tore geschossen
Tom hat 5 Tore geschossen
Doch wie sucht man nach einem "."?
Da ich hier nach einem Satz suche, würde ich gerne einen Punkt am Schluss machen. So sieht nun meine Regex aus.
Tim hat . Tore geschossen.
Es hat funktioniert! Tim hat 2 Tore geschossen.
matcht.
Jedoch stimmt jetzt der Satz Tim hat 2 Tore geschossen!
auch überein. Dies liegt daran, dass der Punkt kein Satzzeichen ist. Auch hier repräsentiert er nur ein Zeichen. Um nach einem Punkt zu validieren, muss man ein Backslash davor stellen.
Tim hat . Tore geschossen\.
Dies gilt für alle Zeichen, welche bei Regex eine andere Bedeutung haben.
Hinweis
Die Punkte können auch verwendet werden, um nach einer bestimmten Anzahl Zeichen zu validieren.
..........
Bereiche
Um nach Bereichen von Zeichen zu suchen, kann man diese regular expression verwenden.
Lebron James erzielte [40-50] Punkte
Lebron James erzielte 46 Punkte
Lebron James erzielte 38 Punkte
Michael Jordan erzielte 40 Punkte
Hinweis
Es ist auch möglich, nach einem Bereich mit Buchstaben zu suchen.
Abkürzungen
[0-9][ \t\r\n\f\v][A-Za-z0-9_][A-Za-z0-9_][A-Za-z0-9_][A-Za-z0-9_][A-Za-z0-9_][A-Za-z0-9_][A-Za-z0-9_]
So könnte eine fertige Regex aussehen. Diese verlangt eine Ziffer, gefolgt von einem Abstand. Danach kommen sieben Zeichen.
Solche Abfragen können lang und unverständlich werden. Daher gibt es Abkürzungen.
Abgekürzt | Ausgeschrieben | Name | Bedeutung |
---|---|---|---|
\w | [A-Za-z0-9_] | word character | Grossbuchstabe, Kleinbuchstabe, Ziffer, Unterstrich |
\d | [0-9] | digit character | Ziffer |
\s | [ \t\r\n\f\v] | whitespace character | Abstand, Tab, Wagenrücklauf, Zeilenumbruch, Seitenumbruch, Vertikaler Tab |
\W | [^A-Za-z0-9_] | non-word character | Alle Zeichen ausgenommen word characters |
\D | [^0-9] | non-digit character | Alle Zeichen ausgenommen Ziffern |
\S | [^ \t\r\n\f\v] | non-whitespace character | Alle Zeichen ausgenommen whitespace characters |
Verwendet man diese Abkürzungen, so wird die Abfrage kürzer und verständlicher.
\d\s\w\w\w\w\w\w\w
Gruppieren
Oft ist es entscheidend, wie man die Statements gruppiert.
In diesem Beispiel will ich folgende Sätze herausfiltern:
- Ich mag Reis
- Ich mag Nudeln
Ich mag Reis|Nudeln
Führ ich die nun aus, erhalte ich nicht das gewünschte Resultat. Doch wieso?
Mit der Oder-Verknüpfung suche ich nach "Ich mag Reis" oder "Nudeln".
Ich mag Reis|Nudeln
Um korrekt validieren zu können, muss ich die Expression anpassen.
Ich mag (Reis|Nudeln)
Mit Klammern kann man die Abfragen gruppieren.
Ich mag Reis
Ich mag Nudeln
Ich mag keine Nudeln
Mengenangaben
Fix
Vorhin hatten wir folgende Abfrage.
\d\s\w\w\w\w\w\w\w
Diese ist zwar schon sehr übersichtlich. Es geht aber noch besser.
Mithilfe der geschweiften Klammern kann man eine Anzahl angeben.
\d\s\w{7}
In diesem Beispiel müssen es genau 7 Zeichen sein. Man kann aber auch ein Minimum und Maximum setzten.
mu{3,7}h
Hierbei dürften es mindestens 3 und maximal 7 Zeichen sein.
0 oder mehr
Mit einem *
legt man fest, dass das vorherige Zeichen 0 oder mehrmals vorkommen darf.
he*y
hy
heeeeey
hey
1 oder mehr
Mit einem +
legt man fest, dass das vorherige Zeichen einmal oder mehrmals vorkommen darf.
hilfe+
hilfe
hilfeeeee
hilf
Optional
Mit ?
legt man fest, dass die Zeichen vorkommen können aber nicht müssen.
Xander Bogaerts ist ein (guter )?Baseball Spieler
Xander Bogaerts ist ein Baseball Spieler
Xander Bogaerts ist ein guter Baseball Spieler
James Harden ist ein guter Baseball Spieler
Hinweis
Auch hier muss man ein Backslash vor das Fragezeichen schreiben, damit man nach ihm suchen kann.
Anker
Diese Regex beginnt mit einem ^
und endet mit einem $
. Das bedeutet, dass sie nur matcht, wenn alles dazwischen zu 100% matcht. Wenn also zu Beginn oder am Ende ein anderes Wort vorkommt, so stimmt die Regex nicht.
^regular expressions sind nützlich$
regular expressions sind nützlich
ich denke regular expressions sind nützlich
regular expressions sind nützlich, so finde ich
Caret
Das ^
Symbol kehrt die Aussage der Expression um.
^baseball
Jedes Wort bis auf baseball
matcht.
Praxis
Oben haben wir jeweils einen String gefunden. Doch was nun? Was kann man mit diesem String tun?
Bis jetzt verwendete ich Regex ausschliesslich zur Validierung von Formularen. Dies muss man aber nicht tun.
Erstellt man ein Formular, so gibt es beim input
verschiedene types
, welche man verwenden kann. Diese validieren dann die Eingabe.
<input type="email" placeholder="Mail" />
Mit einem title
kann sogar eine eigene Fehlermeldung mitgeben. Jedoch zieht diese Validierung einen Nachteil mit sich:
Ungenauigkeit - Es wird auf grobe Fehler geschaut. Jedoch werden, meiner Meinung nach, wichtige Dinge nicht validiert.
Dieses Problem löst Regex. Man kann nämlich seine eigene Abfrage dafür schreiben. Meine sieht folgendermassen aus:
^[^\.](\.|\w|!|#|\$|%|&|'|\*|\+|-|\/|=|\?|^|_|`|{|\||}|~){0,64}@[a-z-]+\.\w+
Nun gibt es mehrere Möglichkeiten, diese Regex zu verwenden.
Variante 1
Diese Lösung erfordert kein JS. In HTML gibt man das Pattern im input Element an.
<input
class="tel"
placeholder="Telefonnummer"
pattern="(\+41|0041|0)79\d{3}\d{2}\d{2}"
/>
Nun kann man das input Element stylen, wenn die Regex nicht zutrifft.
.tel:invalid {
border-color: rgb(255, 79, 102);
}
Vorteile
Würde man die Validierung in JS durchführen, so müsste man die Nummer zuerst in einen String umwandeln. Dies ist hier nicht der Fall. Zudem ist beim Ausfüllen des Formulars immer klar, ob die Eingabe stimmt.
Nachteil
Das Erlauben von Abständen ist möglich aber nicht leicht. Man könnte zwar die Regex so erweitern, dass Leerzeichen erlaubt sind. Dies würde die expression aber unübersichtlicher machen.
Variante 2
Diese Lösung erfordert HTML und JS. Mit onfocusout
kann man eine Funktion aufrufen, wenn das Element nicht mehr im Fokus ist.
<input id="plz" placeholder="PLZ" onfocusout="plzFocused()" />
In der JS Funktion wandle ich die Zahlen in einen String um. Danach werden alle Leerzeichen entfernt.
function plzFocused() {
let plz = document.getElementById('plz');
let stringPLZ = plz.value.toString();
let formattedPLZ = stringPLZ.replaceAll(' ', '');
if (formattedPLZ.match(/[1-9][0-6][0-5][0-8]/)) {
correctStyle(plz);
} else {
errorStyle(plz);
}
}
In Zeile 5 setze ich meine Regex ein, um die Eingabe zu validieren. Dazu verwende ich match. Dies ist eine von vielen Regex Methoden. Weitere Methoden:
matchAll()
replace()
replaceAll()
search()
split()
Vorteile
In JS kann ich noch Zeichen entfernen, bevor ich validiere. Zudem ist das HTML sauberer, da die Überprüfung ausgelagert ist.
Nachteile
Man benötigt ein wenig JS Kenntnisse. Zudem muss man anderer Typen zuerst in einen String umwandeln.
Auch ein Nachteil, bei diesem Beispiel, ist, dass man bei der Eingabe der Postleitzahl nicht direkt erkennen kann, ob sie stimmt.
Fazit
Ich finde Regex sehr interessant.
Folgende Links kann ich empfehlen:
Name | Link | Beschreibung |
---|---|---|
I hate regex | https://ihateregex.io/ (opens in a new tab) | Zu den wichtigsten Validierungen findet man hier eine Regex. Zudem gibt es einen Bereich, wo man die expression jeweils testen kann. Leider müssen einige regular expressions noch überarbeitet angepasst werden. |
Regex101 | https://regex101.com/ (opens in a new tab) | Hilfreiches Tool zum Schreiben von Expressions |