3. Reguläre Ausdrücke
Reguläre Ausdrücke
Abschnitt betitelt „Reguläre Ausdrücke“Viele Aufgaben der Textverarbeitung folgen demselben Schema: Prüfen, ob eine Eingabe einem bestimmten Format entspricht. Alle Stellen finden, an denen ein Format vorkommt. Teile eines Textes nach einem Schema ersetzen. Mit einfachen String-Methoden wie in oder startswith lassen sich solche Aufgaben nur behelfsmäßig lösen: Ob ein Text ein @ enthält, sagt wenig darüber aus, ob er eine gültige E-Mail-Adresse ist.
Das passende Werkzeug sind reguläre Ausdrücke (englisch regular expressions, kurz Regex): eine kompakte Notation, die ein Textmuster beschreibt, etwa “zwei Ziffern, Punkt, zwei Ziffern, Punkt, vier Ziffern” für ein Datum. Reguläre Ausdrücke sind eine eigene kleine Sprache innerhalb der Programmiersprache. Einmal gelernt, funktioniert dieselbe Syntax nahezu überall: in Python, JavaScript und Java ebenso wie in der Suche von VS Code, in Datenbankabfragen und in Kommandozeilenwerkzeugen.
Erste Schritte mit dem re-Modul
Abschnitt betitelt „Erste Schritte mit dem re-Modul“Python stellt reguläre Ausdrücke im Modul re der Standardbibliothek bereit:
import re
text = "Der Kurs beginnt am 15.09.2026 im Raum 214."
match = re.search(r"\d{2}\.\d{2}\.\d{4}", text)if match: print(match.group()) # 15.09.2026re.search() durchsucht den Text nach der ersten Stelle, auf die das Muster passt, und liefert ein Match-Objekt oder None, wenn nichts passt. Das Muster \d{2}\.\d{2}\.\d{4} bedeutet, Baustein für Baustein gelesen: zwei Ziffern, ein Punkt, zwei Ziffern, ein Punkt, vier Ziffern.
Die Bausteine
Abschnitt betitelt „Die Bausteine“Ein regulärer Ausdruck besteht aus gewöhnlichen Zeichen, die für sich selbst stehen, und aus Sonderzeichen mit eigener Bedeutung. Zuerst der Überblick, danach die Gruppen im Einzelnen:
| Baustein | Bedeutung | Beispiel | passt auf |
|---|---|---|---|
abc | genau diese Zeichen | Raum | ”Raum” |
. | ein beliebiges Zeichen | H.t | ”Hut”, “Hit”, “H9t” |
[abc] | eines der Zeichen a, b, c | [aeiou] | einen Vokal |
[a-z] | ein Zeichen aus dem Bereich | [0-5] | 0 bis 5 |
[^abc] | jedes Zeichen außer a, b, c | [^0-9] | keine Ziffer |
\d | eine Ziffer, wie [0-9] | \d\d | ”42” |
\w | Buchstabe, Ziffer oder _ | \w+ | ”word_1” |
\s | Leerzeichen, Tab, Zeilenumbruch | \s | ” “ |
* | Vorheriges 0-mal oder öfter | ab* | ”a”, “ab”, “abbb” |
+ | Vorheriges 1-mal oder öfter | ab+ | ”ab”, “abbb” |
? | Vorheriges 0- oder 1-mal | ab? | ”a”, “ab” |
{n} | Vorheriges genau n-mal | \d{4} | ”2026” |
{n,m} | Vorheriges n- bis m-mal | \d{1,3} | ”7”, “42”, “255” |
^ | Anfang des Textes | ^Der | ”Der…” am Anfang |
$ | Ende des Textes | \.png$ | ”…png” am Ende |
(...) | Gruppe | (ab)+ | ”ab”, “abab” |
a|b | a oder b | png|jpg | ”png” oder “jpg” |
Zeichenklassen: Welche Zeichen sind erlaubt?
Abschnitt betitelt „Zeichenklassen: Welche Zeichen sind erlaubt?“Eckige Klammern definieren eine Menge erlaubter Zeichen für eine Position. [Jj]a passt auf “Ja” und “ja”. Bereiche werden mit Bindestrich angegeben: [a-zA-Z] ist ein Buchstabe (ohne Umlaute), [0-7] eine Oktalziffer. Ein ^ direkt nach der öffnenden Klammer negiert die Menge: [^"] ist jedes Zeichen außer dem Anführungszeichen.
Für häufig gebrauchte Mengen existieren Abkürzungen: \d (digit) für Ziffern, \w (word) für Buchstaben, Ziffern und Unterstrich, \s (space) für Weißraum. Die Großbuchstaben-Varianten \D, \W, \S bedeuten jeweils das Gegenteil.
Der Punkt . passt auf jedes beliebige Zeichen. Ist ein echter Punkt gemeint, muss er mit Backslash entwertet werden: \.. Das gilt für alle Sonderzeichen; die Suche nach einem Plus, einer Klammer oder einem Fragezeichen schreibt sich \+, \(, \?.
Quantoren: Wie oft?
Abschnitt betitelt „Quantoren: Wie oft?“Ein Quantor bezieht sich stets auf den Baustein direkt davor. \d+ bedeutet: eine oder mehrere Ziffern. [a-z]* bedeutet: null oder mehr Kleinbuchstaben. https? bedeutet: “http”, optional gefolgt von einem “s”. Ein häufiges Missverständnis: ab+ heißt “a, dann ein oder mehrere b”, nicht “ab, mehrfach wiederholt”. Soll sich der Quantor auf eine Zeichenfolge beziehen, braucht es eine Gruppe: (ab)+.
Geschweifte Klammern machen die Anzahl exakt: \d{4} sind genau vier Ziffern, \d{2,4} zwei bis vier, \d{2,} mindestens zwei.
Anker: Wo im Text?
Abschnitt betitelt „Anker: Wo im Text?“Ohne Anker findet re.search() das Muster an beliebiger Stelle: re.search(r"\d{3}", "abc12345") meldet einen Treffer. Anker binden das Muster an eine Position: ^ an den Textanfang, $ an das Textende. Das Muster ^\d{4}$ passt nur, wenn der gesamte Text aus exakt vier Ziffern besteht. Für Wortgrenzen gibt es \b: r"\bRaum\b" findet “Raum”, aber nicht “Raumschiff”.
Für die typische Validierungsaufgabe (“Ist diese Eingabe als Ganzes gültig?”) bietet Python re.fullmatch(), das das Muster automatisch auf den gesamten String bezieht:
def is_postal_code(text): """Check for a valid Austrian postal code.""" return re.fullmatch(r"[1-9]\d{3}", text) is not None
print(is_postal_code("4020")) # Trueprint(is_postal_code("40201")) # Falseprint(is_postal_code("A-4020")) # FalseÖsterreichische Postleitzahlen sind vierstellig und beginnen nicht mit 0, daher [1-9] an der ersten Position.
Muster entwickeln: ein Arbeitsbeispiel
Abschnitt betitelt „Muster entwickeln: ein Arbeitsbeispiel“Reguläre Ausdrücke entstehen nicht in einem Wurf, sondern iterativ. Als Beispiel dient der Timecode aus Kapitel 1: 01:00:02:11, also HH:MM:SS:FF.
- Grobstruktur: vier Zahlenpaare, durch Doppelpunkte getrennt:
r"\d{2}:\d{2}:\d{2}:\d{2}". Das passt, allerdings auch auf99:99:99:99. - Verfeinerung: Minuten und Sekunden laufen von 00 bis 59, die erste Ziffer ist also 0 bis 5:
[0-5]\d. Bei 25 fps laufen die Frames von 00 bis 24:[01]\d|2[0-4](“0 oder 1, dann eine Ziffer; oder 2, dann 0 bis 4”). - Zusammengesetzt und als Ganzes geprüft:
pattern = r"\d{2}:[0-5]\d:[0-5]\d:([01]\d|2[0-4])"
print(re.fullmatch(pattern, "01:00:02:11") is not None) # Trueprint(re.fullmatch(pattern, "01:61:02:11") is not None) # Falseprint(re.fullmatch(pattern, "01:00:02:25") is not None) # FalseNach diesem Verfahren entsteht jedes brauchbare Muster: mit einer laxen Version beginnen, Gegenbeispiele suchen, verschärfen. Dazu gehört das passende Werkzeug:
Gruppen: Teile extrahieren
Abschnitt betitelt „Gruppen: Teile extrahieren“Runde Klammern gruppieren nicht nur, sie fangen auch: Der Teil des Treffers, der auf eine Gruppe entfällt, ist anschließend einzeln abrufbar. Damit werden reguläre Ausdrücke vom Prüfwerkzeug zum Extraktionswerkzeug:
text = "Camera B, clip 0047, recorded on 15.09.2026"
m = re.search(r"(\d{2})\.(\d{2})\.(\d{4})", text)if m: print(m.group()) # 15.09.2026 (the whole match) print(m.group(1)) # 15 (first group: day) print(m.group(2)) # 09 (second group: month) print(m.group(3)) # 2026 (third group: year)Bei mehreren Gruppen wird das Durchzählen fehleranfällig. Benannte Gruppen mit (?P<name>...) machen das Muster länger, den Zugriff aber eindeutig:
pattern = r"(?P<day>\d{2})\.(?P<month>\d{2})\.(?P<year>\d{4})"m = re.search(pattern, text)print(m.group("year")) # 2026Ein realistisches Beispiel aus der Medienproduktion: Dateien werden nach dem Schema project_scene-take_camera.extension benannt, etwa commercial_03-2_A.mp4. Ein Muster mit benannten Gruppen zerlegt solche Namen in ihre Bestandteile:
pattern = r"(?P<project>\w+)_(?P<scene>\d{2})-(?P<take>\d+)_(?P<camera>[A-Z])\.(?P<extension>\w+)"
m = re.fullmatch(pattern, "commercial_03-2_A.mp4")if m: print(f"scene {m.group('scene')}, take {m.group('take')}, camera {m.group('camera')}")Alternativen
Abschnitt betitelt „Alternativen“Der senkrechte Strich | trennt Alternativen: png|jpg|gif passt auf eines der drei Wörter. Ohne Klammern erstreckt sich die Alternative auf das gesamte Muster links und rechts des Strichs; in der Regel grenzt man sie deshalb mit einer Gruppe ein: \.(png|jpg|gif)$ passt auf Dateinamen mit einer dieser drei Endungen.
Die Funktionen des re-Moduls im Überblick
Abschnitt betitelt „Die Funktionen des re-Moduls im Überblick“| Funktion | Zweck | liefert |
|---|---|---|
re.search(p, text) | erstes Vorkommen an beliebiger Stelle | Match oder None |
re.fullmatch(p, text) | passt der gesamte Text? | Match oder None |
re.findall(p, text) | alle Vorkommen | Liste von Strings/Tupeln |
re.finditer(p, text) | alle Vorkommen | Iterator von Match-Objekten |
re.sub(p, repl, text) | Vorkommen ersetzen | neuer String |
re.split(p, text) | Text am Muster zerteilen | Liste |
Daneben existiert re.match(), das nur am Textanfang prüft. Es sorgt regelmäßig für Verwirrung; mit search und fullmatch sind alle Anwendungsfälle klarer abgedeckt.
findall: alle Treffer einsammeln
Abschnitt betitelt „findall: alle Treffer einsammeln“log = """2026-09-15 08:03:12 INFO render started: intro.mp42026-09-15 08:41:55 ERROR out of memory: scene_04.mp42026-09-15 09:12:31 INFO render finished: outro.mp42026-09-15 09:13:02 ERROR file not found: music.wav"""
errors = re.findall(r"ERROR (.+)", log)print(errors)# ['out of memory: scene_04.mp4', 'file not found: music.wav']Enthält das Muster genau eine Gruppe, liefert findall deren Inhalt; bei mehreren Gruppen liefert es Tupel. Die Auswertung von Logdateien gehört zu den häufigsten Regex-Anwendungen in der Praxis und ist Gegenstand von Aufgabe 07.
sub: ersetzen mit Rückgriff auf Gruppen
Abschnitt betitelt „sub: ersetzen mit Rückgriff auf Gruppen“re.sub() ersetzt jeden Treffer durch einen Ersatztext. Im Ersatztext darf mit \1, \2 oder \g<name> auf die Gruppen des jeweiligen Treffers zugegriffen werden. Die Umstellung eines Datums vom deutschen ins ISO-Format wird damit zu einer Zeile:
text = "Abgabe: 01.10.2026, Präsentation: 15.10.2026"result = re.sub(r"(\d{2})\.(\d{2})\.(\d{4})", r"\3-\2-\1", text)print(result)# Abgabe: 2026-10-01, Präsentation: 2026-10-15Auch das Suchen-und-Ersetzen in VS Code beherrscht diese Syntax (Regex-Modus über den Knopf .* im Suchfeld aktivieren, im Ersetzen-Feld $1 statt \1). Wer viele Dateien oder Textstellen nach einem Schema umbauen muss, erledigt das damit in Minuten statt Stunden.
Anwendungsfall E-Mail-Adresse
Abschnitt betitelt „Anwendungsfall E-Mail-Adresse“Die Grobstruktur einer E-Mail-Adresse (“lokaler Teil, @, Domain mit mindestens einem Punkt”) lässt sich mit den bisherigen Bausteinen formulieren:
pattern = r"[\w.+-]+@[\w-]+(\.[\w-]+)+"
def is_email(text): return re.fullmatch(pattern, text) is not None
print(is_email("a@b")) # Falseprint(is_email("@@@")) # FalseVor dem @ sind Wortzeichen, Punkte, Plus und Minus erlaubt; danach mindestens ein Domain-Teil und mindestens eine Punkt-Endung. Zur fachlichen Einordnung: Eine vollständige E-Mail-Validierung per Regex ist praktisch nicht sinnvoll machbar. Der zugrunde liegende Standard (RFC 5322) erlaubt weit mehr Formen, als je verwendet werden, und ein standardkonformes Muster füllt eine Bildschirmseite. Die übliche Praxis prüft die Grobstruktur wie oben und verifiziert die Adresse anschließend über ein Bestätigungsmail.
Wann Regex die falsche Lösung ist
Abschnitt betitelt „Wann Regex die falsche Lösung ist“Drei Einschränkungen gehören zu einem professionellen Umgang mit regulären Ausdrücken:
- Einfache Fälle einfach lösen. Ob ein Dateiname auf
.pngendet, prüftname.endswith(".png")kürzer, schneller und lesbarer als jede Regex. Auchin,startswith,splitundstripdecken viele Alltagsfälle ab. - Verschachtelte Strukturen sind prinzipiell ungeeignet. HTML, XML und JSON erlauben beliebig tiefe Verschachtelung. Reguläre Ausdrücke können solche Strukturen aus theoretischen Gründen nicht korrekt erfassen; dafür existieren Parser. Für JSON stellt die Standardbibliothek das
json-Modul bereit (Kapitel 9). - Lesbarkeit hat Vorrang. Ein Muster, das eine Woche später niemand mehr entziffern kann, ist ein Wartungsproblem. Abhilfe schaffen benannte Gruppen, das Zerlegen langer Muster in benannte Teilstrings und ein Kommentar, der den fachlichen Zweck samt zwei Beispielen dokumentiert.
Lernergebnisse: Was Sie nach diesem Kapitel können sollten
Abschnitt betitelt „Lernergebnisse: Was Sie nach diesem Kapitel können sollten“Nach Abschluss dieses Kapitels sollten Schülerinnen und Schüler in der Lage sein:
- Nennen: die Bausteine regulärer Ausdrücke (Zeichenklassen, Quantoren, Anker, Gruppen, Alternativen) und ihre Bedeutung nennen.
- Anwenden: Muster für typische Aufgaben (Postleitzahl, Datum, Timecode, E-Mail, Log-Zeilen, Dateinamen) formulieren und mit einem Werkzeug wie regex101 testen.
- Anwenden: Texte mit
search,fullmatch,findallundsubdurchsuchen, validieren und umformen. - Analysieren: Teilinformationen mit Capture-Gruppen (auch benannten) aus Texten extrahieren.
- Beurteilen: entscheiden, wann ein regulärer Ausdruck das passende Werkzeug ist und wann String-Methoden oder ein Parser vorzuziehen sind.
Passende Übungen
Abschnitt betitelt „Passende Übungen“- Aufgabe 06 - Musterjagd
- Aufgabe 07 - Logdatei-Detektiv