W3docs

Python RegEx

Python reguläre Ausdrücke: Syntax, Sondersequenzen, Gruppen, Lookaheads, Flags und re-Modul-Funktionen mit klaren Beispielen.

Reguläre Ausdrücke (Regex) ermöglichen es, Text anhand flexibler Muster statt exakter Zeichenketten zu suchen, zu extrahieren und zu ersetzen. Pythons eingebautes re-Modul stellt alles Notwendige bereit. Dieses Kapitel behandelt das vollständige Regex-Werkzeugset: Syntax, Sondersequenzen, Quantoren, Gruppen, Lookahead/Lookbehind, Flags und alle wesentlichen re-Funktionen — mit korrekten, ausführbaren Beispielen.

Warum Reguläre Ausdrücke verwenden?

Einfache string-Methoden (str.find(), str.replace(), str.split()) funktionieren gut für festen Text. Reguläre Ausdrücke glänzen, wenn das Muster variiert:

  • Prüfen, ob eine Zeichenkette wie eine E-Mail-Adresse oder Telefonnummer aussieht.
  • Alle Datumsangaben aus einem Dokument extrahieren, unabhängig vom genauen Format.
  • HTML-Tags aus einer Zeichenkette entfernen.
  • Mehrere verschiedene Leerraumsequenzen durch ein einzelnes Leerzeichen ersetzen.

Wenn es darum geht, eine Form zu beschreiben statt einen festen Wert, greift man zu re.

Raw Strings

Regex-Muster werden fast immer als Raw Strings (r'...') geschrieben. Raw Strings behandeln Backslashes als literale Zeichen, was wichtig ist, da Regex viele Backslash-Sequenzen verwendet (\d, \w, \s, \b). Ohne das r-Präfix wären überall doppelte Backslashes nötig:

import re

# Both patterns are identical — raw string is easier to read
re.findall(r'\d+', 'abc 123')   # raw:    r'\d+'
re.findall('\\d+', 'abc 123')   # normal: '\\d+'

Verwenden Sie Raw Strings für jedes Regex-Muster — das ist die universelle Konvention.

Grundlegende Syntax: Metazeichen

Metazeichen sind Zeichen mit besonderer Bedeutung innerhalb eines Musters. Literale Zeichen stimmen genau mit sich selbst überein.

MetazeichenBedeutung
.Beliebiges Zeichen außer einem Zeilenumbruch
^Anfang der Zeichenkette (oder Zeile im MULTILINE-Modus)
$Ende der Zeichenkette (oder Zeile im MULTILINE-Modus)
*Null oder mehr des vorangehenden Elements
+Eines oder mehr des vorangehenden Elements
?Null oder eines des vorangehenden Elements
{n}Genau n Wiederholungen
{n,m}Zwischen n und m Wiederholungen
[...]Zeichenklasse — eines der aufgelisteten Zeichen
[^...]Negierte Klasse — jedes Zeichen, das nicht aufgelistet ist
|Alternation — entweder der linke oder rechte Ausdruck
()Erfassungsgruppe
\Metazeichen maskieren oder Sondersequenz einleiten

Um ein literales Metazeichen wie . oder * zu treffen, maskieren Sie es mit einem Backslash: \. trifft einen echten Punkt.

Sondersequenzen

Sondersequenzen sind Kurzschreibweisen für Zeichenklassen, die in realen Mustern häufig vorkommen.

SequenzTrifft auf
\dJede Ziffer — entspricht [0-9]
\DJede Nicht-Ziffer
\wWortzeichen: Buchstaben, Ziffern, Unterstrich
\WNicht-Wortzeichen
\sLeerzeichen: Leerzeichen, Tabulator, Zeilenumbruch
\SKein Leerzeichen
\bWortgrenze (nullbreite Assertion)
\BKeine Wortgrenze
import re

print(re.findall(r'\d+', 'I have 3 cats and 12 dogs'))
# ['3', '12']

print(re.findall(r'\w+', 'hello_world 123'))
# ['hello_world', '123']

print(re.findall(r'\bPython\b', 'Python Pythonista Python3'))
# ['Python']  — word boundary prevents partial matches

\b ist besonders nützlich: Es trifft die Position zwischen einem Wortzeichen und einem Nicht-Wortzeichen, sodass \bPython\b das eigenständige Wort „Python" trifft, nicht jedoch „Pythonista" oder „Python3".

Quantoren

Quantoren steuern, wie oft das vorangehende Element übereinstimmen muss.

import re

print(re.findall(r'a*', 'baaa'))   # ['', 'aaa', '']
print(re.findall(r'a+', 'baaa'))   # ['aaa']
print(re.findall(r'a?', 'baaa'))   # ['', 'a', 'a', 'a', '']
print(re.findall(r'a{3}', 'baaa')) # ['aaa']

Gieriges vs. faules Matching

Standardmäßig sind Quantoren gierig — sie treffen so viel Text wie möglich. Durch Anhängen von ? nach dem Quantor wird er faul (trifft so wenig wie möglich).

import re

html = '<b>bold</b> and <i>italic</i>'

print(re.findall(r'<.*>', html))
# ['<b>bold</b> and <i>italic</i>']  — greedy: matches from first < to last >

print(re.findall(r'<.*?>', html))
# ['<b>', '</b>', '<i>', '</i>']  — lazy: matches each individual tag

Faule Quantoren sind unerlässlich beim Parsen strukturierten Texts wie HTML- oder JSON-Fragmente.

Zeichenklassen

Eine Zeichenklasse [...] trifft jedes einzelne Zeichen aus der aufgelisteten Menge. Verwenden Sie - für Bereiche und ^ am Anfang, um die Klasse zu negieren.

import re

print(re.findall(r'[aeiou]', 'hello world'))
# ['e', 'o', 'o']

print(re.findall(r'[0-9]', 'a1b2c3'))
# ['1', '2', '3']

print(re.findall(r'[^aeiou\s]+', 'hello world'))
# ['h', 'll', 'w', 'rld']  — consonants only (not vowels, not spaces)

Häufige vordefinierte Bereiche: [a-z] Kleinbuchstaben, [A-Z] Großbuchstaben, [0-9] Ziffern, [a-zA-Z0-9] alphanumerisch.

Anker

Anker verbrauchen keine Zeichen — sie behaupten eine Position in der Zeichenkette.

import re

print(re.findall(r'^Python', 'Python is great'))
# ['Python']  — matches only if 'Python' is at the start

print(re.findall(r'great$', 'Python is great'))
# ['great']  — matches only if 'great' is at the end

print(re.findall(r'^Python', 'Learn Python'))
# []  — 'Python' is not at the start of this string

Informationen zum re.MULTILINE-Flag, mit dem ^ und $ zeilenweise statt zeichenkettenweise angewendet werden, finden Sie später in diesem Kapitel.

Alternation

Das Pipe-Zeichen | wirkt wie ein logisches ODER zwischen zwei Ausdrücken.

import re

print(re.findall(r'cat|dog', 'I have a cat and a dog'))
# ['cat', 'dog']

print(re.findall(r'colou?r|colour', 'color and colour'))
# ['color', 'colour']

Erfassungsgruppen

Klammern () erstellen eine Erfassungsgruppe. Gruppen ermöglichen das Extrahieren von Teilübereinstimmungen. re.search() gibt ein Match-Objekt zurück; rufen Sie darauf .group(n) oder .groups() auf.

import re

match = re.search(r'(\d{4})-(\d{2})-(\d{2})', '2023-10-05')
if match:
    print(match.group(0))   # '2023-10-05'  — entire match
    print(match.group(1))   # '2023'
    print(match.groups())   # ('2023', '10', '05')

Benannte Gruppen

Benennen Sie eine Gruppe mit (?P<name>...), um statt über die Position über den Namen auf sie zuzugreifen. Das macht Muster viel einfacher zu pflegen.

import re

match = re.search(
    r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})',
    '2023-10-05'
)
if match:
    print(match.group('year'))   # '2023'
    print(match.groupdict())     # {'year': '2023', 'month': '10', 'day': '05'}

Nicht-erfassende Gruppen

Verwenden Sie (?:...), wenn Sie gruppieren, aber den Wert nicht erfassen möchten.

import re

print(re.findall(r'(?:Mr|Mrs|Ms)\.? \w+', 'Mr. Smith and Mrs. Jones'))
# ['Mr. Smith', 'Mrs. Jones']

Lookahead und Lookbehind

Lookahead ((?=...)) und Lookbehind ((?<=...)) behaupten, dass etwas nach oder vor der Übereinstimmung folgt, ohne es in das Ergebnis einzuschließen. Sie sind nullbreit: Sie verbrauchen keine Zeichen.

import re

# Positive lookahead — find numbers followed by 'dollars'
print(re.findall(r'\d+(?= dollars)', '100 dollars and 200 euros'))
# ['100']

# Negative lookahead — find numbers NOT followed by 'dollars'
print(re.findall(r'\b\d+\b(?! dollars)', '100 dollars and 200 euros'))
# ['200']

# Positive lookbehind — extract domain from email addresses
emails = 'Contact [email protected] or [email protected]'
print(re.findall(r'(?<=@)\w+\.\w+', emails))
# ['example.com', 'test.org']

Lookbehind-Muster müssen in Python eine feste Breite haben — * oder + dürfen darin nicht verwendet werden.

Das re-Modul: Kernfunktionen

re.search() — Erste Übereinstimmung finden

Gibt ein Match-Objekt für die erste Stelle zurück, an der das Muster übereinstimmt, oder None, wenn keine Übereinstimmung gefunden wird.

import re

text = 'apple banana apple'
match = re.search(r'banana', text)
if match:
    print(match.group())   # 'banana'
    print(match.span())    # (6, 12)

re.match() — Nur am Anfang treffen

Wie re.search(), aber das Muster muss am Anfang der Zeichenkette übereinstimmen.

import re

print(bool(re.match(r'\d+', 'abc123')))   # False — no digit at start
print(bool(re.search(r'\d+', 'abc123')))  # True  — digit found anywhere

Verwenden Sie re.search(), wenn Sie ein Muster irgendwo suchen möchten; verwenden Sie re.match(), wenn das Muster am Anfang stehen muss.

re.fullmatch() — Gesamte Zeichenkette treffen

Das Muster muss die gesamte Zeichenkette von Anfang bis Ende treffen.

import re

print(bool(re.fullmatch(r'\d{5}', '12345')))   # True  — exactly 5 digits
print(bool(re.fullmatch(r'\d{5}', '123456')))  # False — too long
print(bool(re.fullmatch(r'\d{5}', '1234X')))   # False — non-digit present

re.fullmatch() ist ideal für die Eingabevalidierung (Postleitzahlen, Telefonnummern usw.).

re.findall() — Alle nicht überlappenden Übereinstimmungen

Gibt eine Liste aller Übereinstimmungen zurück. Enthält das Muster Gruppen, wird eine Liste von Tupeln zurückgegeben.

import re

print(re.findall(r'\d+', 'abc 123 def 456'))
# ['123', '456']

# With a group — returns list of group values
print(re.findall(r'(\w+)@(\w+\.\w+)', '[email protected] [email protected]'))
# [('alice', 'example.com'), ('bob', 'test.org')]

re.finditer() — Iterator von Match-Objekten

Wie re.findall(), gibt aber Match-Objekte einzeln zurück. Nützlich für große Texte oder wenn Positionsinformationen benötigt werden.

import re

for m in re.finditer(r'\d+', 'abc 123 def 456'):
    print(m.group(), m.start(), m.end())
# 123 4 7
# 456 12 15

re.sub() — Übereinstimmungen ersetzen

Ersetzt jedes Vorkommen des Musters durch eine Ersetzungszeichenkette oder den Rückgabewert einer Funktion.

import re

text = 'apple banana apple'
print(re.sub(r'apple', 'orange', text))
# 'orange banana orange'

# Limit replacements
print(re.sub(r'apple', 'orange', text, count=1))
# 'orange banana apple'

# Backreferences in replacement — reformat a date
print(re.sub(r'(\d{4})-(\d{2})-(\d{2})', r'\3/\2/\1', '2023-10-05'))
# '05/10/2023'

re.split() — Nach Muster aufteilen

Teilt die Zeichenkette bei jedem Vorkommen des Musters auf.

import re

print(re.split(r',\s*', 'apple, banana, cherry, date'))
# ['apple', 'banana', 'cherry', 'date']

# Limit the number of splits
print(re.split(r',\s*', 'apple, banana, cherry, date', maxsplit=2))
# ['apple', 'banana', 'cherry, date']

Muster kompilieren mit re.compile()

Wenn dasselbe Muster viele Male verwendet wird, kompilieren Sie es einmalig mit re.compile(), um die Leistung zu verbessern. Das resultierende Musterobjekt verfügt über alle gleichen Methoden (findall, search, sub usw.).

import re

# Compile once
digit_pattern = re.compile(r'\d+')

# Reuse many times
print(digit_pattern.findall('abc 123 def 456'))   # ['123', '456']
print(digit_pattern.sub('NUM', 'abc 123 def 456')) # 'abc NUM def NUM'
print(digit_pattern.search('xyz 99'))              # <re.Match object ...>

Die Kompilierung ist besonders wertvoll innerhalb von Schleifen oder häufig aufgerufenen Funktionen.

Flags

Flags ändern das Matching-Verhalten. Sie werden als letztes Argument an jede re-Funktion übergeben oder beim Aufruf von re.compile() angegeben. Mehrere Flags können mit | kombiniert werden.

FlagKurzformWirkung
re.IGNORECASEre.IGroß-/Kleinschreibung ignorieren
re.MULTILINEre.M^ und $ treffen Anfang/Ende jeder Zeile
re.DOTALLre.S. trifft auch Zeilenumbrüche
re.VERBOSEre.XLeerzeichen und Kommentare im Muster erlauben
import re

# IGNORECASE
print(re.findall(r'hello', 'Hello HELLO hello', re.IGNORECASE))
# ['Hello', 'HELLO', 'hello']

# MULTILINE — ^ matches the start of each line
text = 'first line\nsecond line\nthird line'
print(re.findall(r'^\w+', text, re.MULTILINE))
# ['first', 'second', 'third']

# DOTALL — . matches newline characters
print(re.findall(r'<.*?>', '<div>\n<p>text</p>\n</div>', re.DOTALL))
# ['<div>', '<p>', '</p>', '</div>']

# VERBOSE — write readable patterns with comments
date_pattern = re.compile(r'''
    (?P<year>\d{4})   # four-digit year
    -
    (?P<month>\d{2})  # two-digit month
    -
    (?P<day>\d{2})    # two-digit day
''', re.VERBOSE)
print(date_pattern.search('2023-10-05').groupdict())
# {'year': '2023', 'month': '10', 'day': '05'}

Benutzereingaben maskieren mit re.escape()

Wenn Sie ein Muster aus vom Benutzer geliefertem Text aufbauen, maskieren Sie diesen immer zuerst, um unbeabsichtigte Metazeichen-Interpretation zu verhindern.

import re

user_input = 'hello.world'
# Without escaping, '.' matches any character
# With escaping, '\.' matches a literal dot
safe_pattern = re.escape(user_input)
print(safe_pattern)                                    # 'hello\\.world'
print(bool(re.search(safe_pattern, 'say hello.world')))  # True
print(bool(re.search(safe_pattern, 'say helloXworld')))  # False

Praktische Beispiele

E-Mail-Adresse validieren

import re

def is_valid_email(email):
    pattern = r'^[\w.+-]+@[\w-]+\.[a-zA-Z]{2,}$'
    return bool(re.fullmatch(pattern, email))

print(is_valid_email('[email protected]'))   # True
print(is_valid_email('bad-email@'))         # False

Alle URLs aus Text extrahieren

import re

text = 'Visit https://www.example.com or http://test.org for details.'
urls = re.findall(r'https?://[\w./-]+', text)
print(urls)
# ['https://www.example.com', 'http://test.org']

Überflüssige Leerzeichen entfernen

import re

messy = '  hello    world   Python  '
clean = re.sub(r'\s+', ' ', messy).strip()
print(clean)  # 'hello world Python'

Eine Log-Zeile parsen

import re

log = '2023-10-05 14:32:11 ERROR Failed to connect to database'
pattern = re.compile(
    r'(?P<date>\d{4}-\d{2}-\d{2}) '
    r'(?P<time>\d{2}:\d{2}:\d{2}) '
    r'(?P<level>\w+) '
    r'(?P<message>.+)'
)
m = pattern.match(log)
if m:
    print(m.group('level'))    # 'ERROR'
    print(m.group('message'))  # 'Failed to connect to database'

Häufige Fallstricke

re.match() vs. re.search()re.match() prüft nur den Anfang der Zeichenkette. Neue Benutzer erwarten oft, dass es überall sucht, und sind verwirrt, wenn None zurückgegeben wird.

Raw Strings vergessen'\d' in einer normalen Python-Zeichenkette ist einfach 'd' mit einem nicht erkannten Escape-Zeichen (oder eine SyntaxWarning in Python 3.12+). Schreiben Sie immer r'\d'.

Gieriges Matching, das zu viel erfasst — Wenn ein .*-Muster mehr als beabsichtigt erfasst, wechseln Sie zu .*? (faul).

Sonderzeichen in Ersetzungsstrings — In re.sub() verweisen Backslash-Sequenzen wie \1 im Ersetzungsstring auf erfasste Gruppen. Um einen literalen Backslash in der Ersetzung einzufügen, schreiben Sie \\.

re.findall() mit Gruppen — Wenn das Muster Gruppen enthält, gibt re.findall() die Gruppen zurück, nicht die vollständige Übereinstimmung. Verwenden Sie eine nicht-erfassende Gruppe (?:...), wenn Sie die vollständige Übereinstimmung möchten.

Kurzreferenz

AufgabeFunktion
Erste Übereinstimmung findenre.search(pattern, text)
Alle Übereinstimmungen findenre.findall(pattern, text)
Übereinstimmungen iterierenre.finditer(pattern, text)
Am Anfang treffenre.match(pattern, text)
Gesamte Zeichenkette treffenre.fullmatch(pattern, text)
Ersetzenre.sub(pattern, repl, text)
Aufteilenre.split(pattern, text)
Für Wiederverwendung kompilierenre.compile(pattern)
Benutzereingabe maskierenre.escape(text)

Verwandte Kapitel

  • Python Strings — string-Methoden, die Regex bei einfacheren Textaufgaben ergänzen.
  • Modify Strings — eingebaute Methoden wie replace() und split(), die Regex vermeiden, wenn Muster fest sind.
  • Python File Handling — Dateien zeilenweise lesen, um Regex in großem Maßstab anzuwenden.
  • Python Try/Except — Fehlerbehandlung bei Regex-Mustern, die aus Benutzereingaben kompiliert werden.
  • Python Functions — Regex-Logik in wiederverwendbare Funktionen kapseln.

Übungen

Übung
Was stellt das 're'-Modul in Python bereit?
Was stellt das 're'-Modul in Python bereit?
Was this page helpful?