- 1 Section
- 10 Lessons
- unbegrenzt
- Reguläre Ausdrücke & Textverarbeitung10
- 1.1Was sind Reguläre Ausdrücke?
- 1.2Grundzeichen: Literale, Zeichenklassen, Quantoren
- 1.3Anker, Gruppen und Alternation
- 1.4Gierige vs. faule Quantoren
- 1.5Regex in Python: re-Modul
- 1.6Regex in JavaScript
- 1.7grep, sed, awk – Regex auf der Kommandozeile
- 1.8Regex für Validierung: E-Mail, IP, PLZ, Datum
- 1.9Regex in Datenbanken: LIKE, REGEXP
- 1.10Aufgaben Reguläre Ausdrücke
Regex in JavaScript
Nachdem du in L5 Python's re-Modul kennengelernt hast, geht's hier um JavaScript. Anders als Python hat JS eine eingebaute Regex-Syntax: das Pattern steht direkt im Code zwischen zwei Slashes – wie ein eigener Datentyp. Das macht JS-Regex kompakt, ist aber auch eine eigene Lernkurve.
Diese Lektion zeigt die zwei Möglichkeiten Regex in JS zu erzeugen, alle wichtigen String- und RegExp-Methoden, das Flag-System, und die Eigenheiten gegenüber Python. Wer Frontend mit DOM-Manipulation und Form-Validierung macht, braucht Regex ständig.
1) Zwei Wege Regex zu erzeugen
In JavaScript hast du zwei Möglichkeiten ein Regex-Objekt zu erstellen. Regex-Literal (mit Slashes) und RegExp-Konstruktor:
Wann was nutzen?
- Literal: fast immer. Kompakter, kein doppeltes Escape, syntaxgehighlightet in Editoren.
- Konstruktor: wenn das Pattern dynamisch zur Laufzeit gebaut wird – z.B. aus User-Eingabe oder einer Variable.
Wichtig: im Konstruktor sind die Patterns Strings – Backslashes müssen verdoppelt werden. \d als Pattern-Literal, aber "\\d" im String. Im Literal hast du keinen String-Escape-Schritt: was du tippst, ist was die Engine bekommt.
2) Die wichtigsten Methoden
Anders als Python (alle Funktionen im re-Modul) hat JS die Regex-Operationen auf zwei Stellen verteilt: einige auf dem RegExp-Objekt, einige auf String-Objekten. Das ist verwirrend am Anfang. Übersicht:
g-Flag kann mehrfach aufgerufen werden.repl kann String mit $1 oder Funktion sein. Mit g alle, sonst nur erstes.match() ist tückisch wegen unterschiedlichem Verhalten je nach g-Flag – heute lieber matchAll().3) Die Flags
JavaScript-Regex haben sechs Flags, jeweils ein einzelner Buchstabe. Im Literal stehen sie hinter dem schließenden Slash, im Konstruktor im zweiten Argument:
| Flag | Name | Wirkung |
|---|---|---|
g | global | Alle Treffer finden (statt nur erstem). Pflicht für matchAll/replaceAll. |
i | insensitive | Case-insensitive – Groß/Klein egal. |
m | multiline | ^/$ matchen Zeilenanfang/-ende statt String. |
s | dotAll | . matched auch Newlines (ES2018). |
u | unicode | Korrekte Unicode-Behandlung, Unterstützung für \u{...} |
y | sticky | Match nur ab lastIndex, nirgendwo anders. |
Flags kombinieren: einfach aneinanderhängen. /pattern/gim = global, insensitive, multiline. Reihenfolge egal, gleiche Flags doppelt verboten.
4) Interaktiver Flag-Playground
Spiel mit den Flags und sieh die Auswirkungen sofort. Klick die Flags an/aus und beobachte wie sich die Treffer ändern:
- Ohne Flags: nur „Hallo" am Anfang (case-sensitive) wird gefunden, alle anderen Vorkommen werden mit
^-Anker am Stringanfang abgeblockt. - + g: macht keinen Unterschied weil
^nur einmal matched (Stringanfang). - + i: jetzt findet er auch HALLO als Variante.
- + m: jetzt matched
^auch nach Newline → alle Zeilen-Anfänge. - g + i + m zusammen: alle Hallo-Varianten am Anfang jeder Zeile, case-insensitive.
5) Named Groups und Backreferences
Wie in L3 erklärt: Named Groups machen Code lesbar. JavaScript-Syntax: (?<name>...) – ohne das P von Python:
Im Replace-Pattern referenzierst du Named Groups mit $<name>:
Verfügbar seit ES2018 – moderne Browser und Node.js können das. In älteren Umgebungen brauchst du nummerierte Groups ($1, $2, $3).
6) replace mit Funktion: maximale Flexibilität
Wie Python's re.sub: JavaScript's replace akzeptiert eine Funktion als zweites Argument. Die Funktion bekommt den Match plus alle Gruppen und gibt den Ersatz zurück. Damit löst du komplexe Transformationen elegant:
Die Funktion bekommt als Parameter: 1. den ganzen Match, 2.+ alle nummerierten Gruppen, dann den Offset im Original-String, den Original-String, und (bei Named Groups) das groups-Objekt. Sehr mächtig.
7) Lookbehind: in JavaScript erst seit kurzem
Eine wichtige Eigenheit: Lookbehind-Assertions (?<=...) und (?<!...) sind in JavaScript erst seit ES2018 verfügbar. Ältere Browser (Internet Explorer, Safari vor 16.4) unterstützen sie nicht. Wenn du für ältere Targets entwickelst: vermeiden oder polyfillen.
Lookahead dagegen ((?=...), (?!...)) gibt's in JavaScript schon ewig – ungefähr ES3. Bei alten Targets ist nur Lookbehind das Problem.
8) Python vs. JavaScript – Cheat-Sheet
Wenn du zwischen beiden Sprachen wechselst, hilft eine Vergleichstabelle. Die Patterns sind 95% identisch, nur die Drumherum-API unterscheidet sich:
| Aufgabe | Python (re-Modul) | JavaScript |
|---|---|---|
| Pattern erstellen | re.compile(r"\d+") | /\d+/ oder new RegExp("\\d+") |
| Test ob matched | re.search(pat, s) | re.test(s) |
| Erstes Match | re.search() | re.exec() oder s.match() |
| Alle Matches | re.findall() | [...s.matchAll(re)] |
| Ganzer String matched? | re.fullmatch() | /^...$/ nutzen |
| Ersetzen | re.sub(pat, repl, s) | s.replace(re, repl) |
| Teilen | re.split(pat, s) | s.split(re) |
| Named Groups | (?P<name>...) | (?<name>...) |
| Backref im Replace | \1 oder \g<name> | $1 oder $<name> |
| Case-Insensitive | re.IGNORECASE | /i |
| Multiline | re.MULTILINE | /m |
| Dot matches all | re.DOTALL | /s |
Bei der täglichen Arbeit reicht oft eine Sprache. Aber für IT-Profis ist es nicht ungewöhnlich beide zu nutzen (Backend Python, Frontend JS) – diese Tabelle hilft beim Wechsel.
9) Stolperfallen in JavaScript-Regex
Spezifische Fallen die dich in JS treffen:
- exec() mit g-Flag und lastIndex: bei wiederholtem Aufruf läuft die Engine intern weiter. Wenn du den selben Regex auf einen anderen String nutzt, ist der lastIndex noch vom alten – kann verwirren. Lösung:
re.lastIndex = 0manuell, odermatchAll()nutzen. - match() Verhalten je nach g: ohne g → Array mit Match + Gruppen. Mit g → Array nur mit Matches, KEINE Gruppen. Das ist eine echte Inkonsistenz. Lösung:
matchAll()mit g-Flag, gibt Iterator von vollständigen Match-Arrays. - String → Regex-Escape: wenn du User-Input in einen Regex packst, kann der enthaltene Sonderzeichen haben. Erst escapen:
str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'). - replace ohne g ersetzt nur erstes:
"a a a".replace(/a/, "X")→ „X a a". Will man alle ersetzen:/a/goder String-replaceAll:"a a a".replaceAll("a", "X"). Ohne g und mit replaceAll → TypeError. - Source-Property: zum Debuggen kannst du
re.sourceundre.flagsanschauen.
10) Frontend-Validierung mit Regex
Ein typischer JS-Use-Case: Formular-Validierung im Browser. Beispiel für eine E-Mail-Eingabe:
HTML5 hat auch pattern-Attribute auf Input-Feldern für deklarative Regex-Validierung:
Der Browser prüft automatisch beim Submit. Wichtig: das pattern wird implizit als ^...$ behandelt – muss den ganzen Wert matchen. Mehr zu Form-Validierung in L8.
11) ReDoS – auch in JavaScript ein Problem
Wie in L4 beschrieben: katastrophales Backtracking kann zu Hängern führen. In JavaScript ist das besonders problematisch wenn User-Input gegen einen schlecht geschriebenen Regex geprüft wird – ein Angreifer kann mit einem speziellen String die Webseite lahmlegen.
Wichtige Verteidigungen:
- Anchor verwenden:
^und$begrenzen die Suche - Negierte Klassen statt lazy:
[^"]*statt.*? - Maximale Input-Länge prüfen: vor dem Regex-Match die Länge limitieren
- Timeout-Mechanismus: in Web Workers ausführen mit Timeout (komplex aber möglich)
- Statisch analysieren: Tools wie
safe-regexodervuln-regex-detectorerkennen problematische Patterns
Mehr zu sicheren Regex in K11 Secure Coding. Beim Debugging kann ein hängendes test() auch ein ReDoS-Symptom sein.
12) Performance-Tipps für JavaScript
Ein paar Faustregeln für schnellen Regex-Code:
- Pattern wiederverwenden: Regex-Literal außerhalb von Loops definieren, nicht in jedem Durchlauf neu.
- test() statt match() wenn du nur ja/nein brauchst – ist schneller und gibt klares Boolean.
- String-Methoden bevorzugen wenn keine Regex nötig:
str.startsWith("x")ist 10x schneller als/^x/.test(str). - Anchor bei test:
/^pattern/bricht früh ab wenn Anfang nicht matched. - Spezifische Patterns:
[a-z]+ist schneller als\w+wenn du wirklich nur Kleinbuchstaben willst.
Zusammenfassung
JavaScript-Regex haben zwei Formen: Literal /pattern/flags (kompakt) und Konstruktor new RegExp(...) (für dynamische Patterns). Hauptmethoden: re.test() (boolean), str.matchAll(re) moderner Iterator (ES2020), str.replace(re, repl) mit String oder Funktion. Flags: g/i/m/s/u/y. Named Groups: (?<name>...), Match hat .groups-Property. Lookbehind erst seit ES2018. Stolperfallen: match() verhält sich je nach g-Flag unterschiedlich (lieber matchAll), replace ohne g ersetzt nur erstes. ReDoS auch in JS ein Sicherheitsrisiko – Input-Länge prüfen.
