Reguläre Ausdrücke zum Ansehen
·
Kursüberblick
1
Die verschwundene Zahlung: Text wörtlich finden
2
Der Fluchtwagen: Zeichenklassen
3
Das zerrissene Telefonbuch: Quantoren
4
Die falschen Anmeldungen: Anker und Validierung
5
Daten in jedem Format: Gruppen und Alternativen
6
Der Zugriff um 3 Uhr nachts: benannte Gruppen und Match-Objekte
7
Die Nacht vor der Story: Ersetzen und Aufteilen
8
Die Herausforderung des Backtrackers: gierig, genügsam, possessiv
9
Die Regeln des Tresors: Lookaround
10
Gleiche Masche: Rückverweise und Bedingungen
11
Der unlesbare Regex: Flags und Kompilieren
12
Die Enttarnung des Backtrackers: Rückblick und ein Tokenizer
CASE-009
Grep & Co. Datendetektei
Fallakte
Auftraggeber
Direktorin Han Byeol
Beweismittel
Der alte Tresor der Detektei, sechs Kandidaten für das neue Passwort und das Kassenbuch im Tresor.
Zum Abschluss des Falls
Die neuen Passwortregeln (mindestens 8 Zeichen, je mindestens eine Ziffer, ein Kleinbuchstabe und ein Sonderzeichen) mit einem einzigen Muster prüfen und die Beträge im Kassenbuch mit Tausenderkommas versehen.
Die Direktorin hockt sich vor den alten Tresor in der Ecke. „Dass der Backtracker den Tresor erwähnt, soll uns nur Angst machen. Trotzdem ändern wir heute das Passwort. Und diesmal halten wir uns an die Regeln.“
Für das neue Passwort gelten drei Regeln, die Reihenfolge ist egal. Ihr Zettel ist auf Koreanisch: (1) mindestens 8 Zeichen, (2) je mindestens eine Ziffer, ein Kleinbuchstabe und ein Sonderzeichen, (3) alles mit einem einzigen regulären Ausdruck prüfen. Darunter stehen die Kandidaten (후보).
규칙 1. 8자 이상
규칙 2. 숫자, 소문자, 특수문자가 각각 하나 이상
규칙 3. 이 모든 걸 정규식 하나로 검사한다
후보:
vault2026!
vault2026
VAULT2026!
v!2
longpassword!
safe#2026boxDir fällt der Satz von der Karte wieder ein: „Vorausgesetzt, ihr könnt alle an derselben Stelle prüfen.“ Genau darum geht es heute.
Erinnere dich an ^, $ und \b aus Lektion 4. Sie fressen kein einziges Zeichen und prüfen nur eine Position: „Ist hier der Anfang?“, „Ist hier eine Wortgrenze?“ Solche Treffer heißen Treffer der Breite null (zero-width).
re.findall(r"\b", "hi yo") # ['', '', '', '']
re.sub(r"\b", "|", "hi yo") # '|hi| |yo|'\b hat vier leere Strings gefunden, also vier Positionen. Mit Lookaround, um das es heute geht, baust du solche Positionsprüfungen mit beliebigen eigenen Bedingungen.
X(?=Y) findet „ein X, auf das Y folgt“. Y wird nur geprüft und gehört nicht zum Treffer. Das nennt man Lookahead.
re.findall(r"\d+(?=원)", "3000원짜리 5개, 합계 15000원") # ['3000', '15000']Der Text ist ein koreanischer Preiszettel: 원 ist Won, die koreanische Währung, 개 heißt „Stück“, 합계 „Summe“. Die 5 in 5개 fällt weg, weil kein 원 dahinter steht, und in den gefundenen Zahlen steckt kein 원. Ideal, wenn du „Zahlen, die auf Won enden“ suchst, aber nur die Zahl haben willst.
Beweislabor
re.search(r"", text)
Rückgabewert
X(?!Y) ist das Gegenteil: „ein X, auf das Y nicht folgt“. Das heißt negatives Lookahead.
re.findall(r"\b(?!tmp)\w+", "tmp_log report tmpfile final") # ['report', 'final']
re.findall(r"\d{3}(?!\d)", "12345 678") # ['345', '678']tmp anfangen“. Direkt nach der Wortgrenze wird geprüft, dass dort kein tmp steht.Bedingungen der Art „dies muss drin sein, das auch und jenes auch“, wie bei Passwortregeln, schreibst du als Lookaheads nebeneinander.
pw = r"(?=.*\d)(?=.*[a-z])(?=.*[^\w\s]).{8,}"| Baustein | prüft |
|---|---|
(?=.*\d) | irgendwo steht eine Ziffer |
(?=.*[a-z]) | irgendwo steht ein Kleinbuchstabe |
(?=.*[^\w\s]) | irgendwo steht ein Sonderzeichen (weder Buchstabe, Ziffer, Unterstrich noch Leerraum) |
.{8,} | frisst tatsächlich mindestens 8 Zeichen |
Alle drei Lookaheads prüfen an derselben Stelle (ganz vorn). Weil sie keine Zeichen fressen, bleibt die Position nach jedem gleich, und die nächste Bedingung startet wieder ganz vorn. Aneinandergehängt ergeben sie deshalb ein „und“ (AND).
cands = ["vault2026!", "vault2026", "VAULT2026!", "v!2", "longpassword!", "safe#2026box"]
[c for c in cands if re.fullmatch(pw, c)] # ['vault2026!', 'safe#2026box']Beweislabor
re.search(r"", text)
Rückgabewert
Dots Tipp
Ein Lookahead späht nur kurz nach vorn, die Pfoten bleiben, wo sie sind. Ich sitze ja auch auf dem Fensterbrett und schaue nur hinaus, rüber springe ich nicht. Deshalb bin ich, egal wie oft ich hinausschaue, immer noch am selben Platz.
Dreh die Richtung um, und du hast Lookbehind. (?<=Y)X heißt „ein X, vor dem Y steht“, (?<!Y)X heißt „ein X, vor dem kein Y steht“.
re.findall(r"(?<=\$)\d+", "$30 and 40 and $5") # ['30', '5']
re.findall(r"(?<!\$)\b\d+", "$30 and 40 and $5") # ['40']Lookbehind hat eine Einschränkung: Pythons re muss fest wissen, wie weit es zurückschaut.
re.compile(r"(?<=a+)b") # PatternError: look-behind requires fixed-width pattern
re.compile(r"(?<=ab|cd)e") # in Ordnung: beide Alternativen sind 2 Zeichen lang
re.compile(r"(?<=a|bc)d") # PatternError: look-behind requires fixed-width patternMehrere Alternativen sind erlaubt, solange alle gleich lang sind. Sind sie unterschiedlich lang, teilst du das Lookbehind in zwei auf und gruppierst sie getrennt, etwa (?:(?<=a)|(?<=bc))d.
Beweislabor
re.search(r"", text)
Rückgabewert
Im Kassenbuch aus dem Tresor kleben die Ziffern zusammen, etwa 1234567, und sind schwer zu lesen. Du musst nur die Positionen finden, an die ein Komma gehört, und dort eins einsetzen. Positionen suchen ist ein Fall für Lookaround.
re.sub(r"(?<=\d)(?=(?:\d{3})+(?!\d))", ",", "1234567 and 89 and 1000")
# '1,234,567 and 89 and 1,000'So liest du es: „Eine Position, vor der eine Ziffer steht ((?<=\d)) und nach der ein oder mehrere Dreierblöcke aus Ziffern folgen ((?:\d{3})+), nach denen die Zahl endet ((?!\d)).“ Diese Position ist kein Zeichen, also löscht sub nichts, sondern schiebt nur das Komma ein.
Mit einer Gruppe im Lookahead findest du sogar überlappende Treffer. Der Trick: Die Position rückt jeweils ein Zeichen weiter, und die Gruppe holt die beiden Zeichen an dieser Stelle heraus.
re.findall(r"(?=(\w\w))", "abc") # ['ab', 'bc']Beweislabor
re.search(r"", text)
Rückgabewert
Du stellst den Prüfer fertig und siebst die Kandidaten. Die Ausgabe ist koreanisch: 통과 heißt „bestanden“, 탈락 heißt „durchgefallen“.
pw = re.compile(r"(?=.*\d)(?=.*[a-z])(?=.*[^\w\s]).{8,}")
for c in cands:
print(f"{c:<14} {'통과' if pw.fullmatch(c) else '탈락'}")
# vault2026! 통과
# vault2026 탈락
# VAULT2026! 탈락
# v!2 탈락
# longpassword! 탈락
# safe#2026box 통과Die Direktorin nimmt keinen der beiden, die bestanden haben. „Sobald es auf einer Kandidatenliste steht, ist es kein Passwort mehr.“ Dann legt sie selbst, ohne dass jemand zusieht, ein neues Passwort fest, das die Regeln erfüllt, und legt nur den Prüfer in den gemeinsamen Werkzeugkasten der Detektei.
Fall abgeschlossen — Ein Werkzeug gebaut, das die Passwortregeln des Tresors mit drei Lookaheads prüft. Von sechs Kandidaten haben nur zwei die Regeln erfüllt. Das Passwort hat die Direktorin selbst geändert. Die Beträge im Kassenbuch mit Tausenderkommas aufbereitet.
"price: 1200won, tax: 120won" per Lookahead nur die Zahlen vor won heraus.re.findall(r"(?<!\d)\d{2}(?!\d)", "1 22 333 44")? Rate zuerst. Warum kommt kein Teil von 333 heraus?Die Spur des Backtrackers
(a+)+$
Den Tresor lasse ich in Ruhe. Stattdessen habe ich Kommissar Kang auf dem Revier drei Briefe geschickt. Könnt ihr beweisen, dass sie von derselben Person stammen? Gewohnheiten bleiben in den Buchstaben hängen.
Das Notizbuch der Direktorin
Lookaround sind Treffer der Breite null. Sie fressen keine Zeichen und prüfen nur Positionen (wie ^ $ \b).
X(?=Y): ein X, auf das Y folgt. X(?!Y): ein X, auf das kein Y folgt.
(?<=Y)X: ein X, vor dem Y steht. (?<!Y)X: ein X, vor dem kein Y steht. Lookbehind nur mit fester Länge.
Aneinandergehängte Lookaheads sind ein AND: (?=.*\d)(?=.*[a-z])(?=.*[^\w\s]).{8,}
sub an gefundenen Positionen löscht nichts, sondern schiebt ein: Tausenderkommas.
Mit einer Gruppe im Lookahead wie (?=(\w\w)) holst du überlappende Treffer heraus.
← Zurück
Lektion 8 · Die Herausforderung des Backtrackers: gierig, genügsam, possessiv
Weiter →
Lektion 10 · Gleiche Masche: Rückverweise und Bedingungen
Über neue Lektionen informiert werden
Wir schicken dir eine E-Mail, wenn dieser Kurs neue Lektionen bekommt oder ein Folgekurs erscheint.
R
ReflexKR
Python und Reflex zum Anfassen. Alle Beispiele wurden mit Reflex 0.10.0 ausgeführt und geprüft.
ReflexKR ist kostenlos und ohne Werbebanner. Wenn es dir geholfen hat, kannst du es mit einem Kaffee unterstützen. ☕ Spendier uns einen Kaffee
Hinweis zu Affiliate-Links© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
Fragen & Antworten
Frag alles zu dieser Lektion. Fragen aus allen Sprachversionen dieser Seite erscheinen hier gemeinsam.