Aufwärmen · Aufgabe 1 von 7
Aufwärmen mit den String-Methoden: Was gibt das aus?
print("2026-09-29".split("-"))// I4.3 · ca. 35 Min. · Aufbau
Nach dieser Lektion finden, prüfen und zerlegen Sie Text mit regulären Ausdrücken und schreiben ihn mit re.sub um.
Danach können Sie
Aufwärmen · Aufgabe 1 von 7
print("2026-09-29".split("-"))Vorhersagen · Aufgabe 2 von 7
import re
text = "Order 42 shipped"
print(re.match(r"\d+", text), re.search(r"\d+", text).group())Üben · Aufgabe 3 von 7
ok = re.____(r"\d{5}", code) is not NoneÜben · Aufgabe 4 von 7
print(len("\n"), len(r"\n"))Üben · Aufgabe 5 von 7
Denksport · Aufgabe 6 von 7
import re
print(re.findall(r"(\w+)@(\w+)\.com", "ada@mail.com, bo@web.com"))Anwenden · Aufgabe 7 von 7
Prüfen Sie Ihr Ergebnis anhand dieser Liste
Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.
Ausgearbeitetes Beispiel
Jede Zeile des Logs hat ein Datum, eine Stufe in Großbuchstaben und eine Nachricht. Das Programm prüft jede Zeile mit fullmatch und einem kompilierten Muster mit benannten Gruppen, überspringt Zeilen, die nicht passen, und verbirgt E-Mail-Adressen mit sub. Zum Schluss sammelt findall Zahlen und die Domains der Adressen.
main.py
import re
# One log line: a date, a level in capitals, then the message.
LINE = re.compile(r"(?P<date>\d{4}-\d{2}-\d{2}) (?P<level>[A-Z]+) (?P<message>.*)")
EMAIL = re.compile(r"[\w.]+@[\w.]+\.\w+")
log = """2026-09-28 INFO user ada@example.com logged in
2026-09-28 ERROR disk full on /dev/sda1
not a log line
2026-09-29 WARNING retry 3 of 5 for bo@example.org"""
for line in log.splitlines():
found = LINE.fullmatch(line)
if found is None:
print("skipped:", line)
continue
message = EMAIL.sub("<email>", found["message"])
print(found["date"], found["level"].lower(), "|", message)
print(re.findall(r"\d+", "retry 3 of 5"))
print(sorted(re.findall(r"@([\w.]+)", log)))
Ausführen mit
python main.pyAusgabe
2026-09-28 info | user <email> logged in
2026-09-28 error | disk full on /dev/sda1
skipped: not a log line
2026-09-29 warning | retry 3 of 5 for <email>
['3', '5']
['example.com', 'example.org']Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.
Übung 1 von 2
Schreiben Sie is_valid_username(name): True, wenn der ganze Name 3 bis 16 Zeichen lang ist, mit einem ASCII-Buchstaben beginnt und sonst nur ASCII-Buchstaben, Ziffern und _ enthält. Schreiben Sie dann hashtags(text): Es liefert die Wörter nach jedem #, ohne das #. "Loving #python and #regex_101!" ergibt ["python", "regex_101"].
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.
match prüft nur den Anfang: "ada!" beginnt gut. fullmatch prüft den ganzen Namen.
Zuerst ein Buchstabe, dann 2 bis 15 weitere Zeichen: [A-Za-z][A-Za-z0-9_]{2,15}.
Setzen Sie das Wort in eine Gruppe, r"#(\w+)", dann liefert findall nur die Gruppe.
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
import re
def is_valid_username(name: str) -> bool:
return re.fullmatch(r"[A-Za-z][A-Za-z0-9_]{2,15}", name) is not None
def hashtags(text: str) -> list[str]:
return re.findall(r"#(\w+)", text)
if __name__ == "__main__":
print(is_valid_username("ada_99"), is_valid_username("ada!"))
print(hashtags("Loving #python and #regex_101!"))
Installieren Sie Python 3.14 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.py
import re
def is_valid_username(name: str) -> bool:
return re.match(r"[A-Za-z]", name) is not None
def hashtags(text: str) -> list[str]:
return re.findall(r"#\w+", text)
if __name__ == "__main__":
print(is_valid_username("ada_99"), is_valid_username("ada!"))
print(hashtags("Loving #python and #regex_101!"))
test_main.py
from main import hashtags, is_valid_username
def test_valid_names():
"""ada_99 und Bob sind gültige Benutzernamen"""
got = is_valid_username("ada_99"), is_valid_username("Bob")
assert got == (True, True), f"für ada_99 und Bob kam {got!r} zurück"
def test_invalid_names():
"""Zu kurz, Ziffer am Anfang, ein ! darin oder 17 Zeichen: alles abgewiesen"""
names = ["ab", "9lives", "ada!", "a" * 17]
got = [is_valid_username(name) for name in names]
assert got == [False, False, False, False], f"für {names!r} kam {got!r} zurück"
def test_hashtags():
"""Hashtags kommen ohne das # zurück"""
got = hashtags("Loving #python and #regex_101!")
assert got == ["python", "regex_101"], f"hashtags gab {got!r} zurück"
def test_no_hashtags():
"""Ein Text ohne # ergibt []"""
got = hashtags("no tags here")
assert got == [], f"hashtags gab {got!r} zurück"
Unter macOS und Linux tippen Sie python3, wo in diesen Befehlen python steht, wie in der ersten Lektion.
Programm ausführen:
python main.pyPrüfungen ausführen (learnrun.py muss im selben Ordner liegen):
python learnrun.py testlearnrun.py herunterladenÜbung 2 von 2
Schreiben Sie parse_log_line(line). Für eine ganze Zeile wie "2026-09-28 ERROR disk full" liefert sie {"date": "2026-09-28", "level": "ERROR", "message": "disk full"}; für jede Zeile, die nicht passt (Stufe kleingeschrieben, keine Nachricht, Text vor dem Datum), liefert sie None. Schreiben Sie dann iso_to_german(text): Es schreibt jedes Datum wie 2026-09-30 als 30.09.2026 und lässt den Rest unverändert.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.
Benennen Sie die Gruppen: (?P<date>\d{4}-\d{2}-\d{2}), dann ein Leerzeichen, (?P<level>[A-Z]+), ein Leerzeichen und (?P<message>.+).
fullmatch weist Text vor dem Datum ab; ist das Ergebnis None, geben Sie None zurück, sonst found.groupdict().
Für die Daten benennen Sie year, month und day und nehmen r"\g<day>.\g<month>.\g<year>" als Ersetzung in re.sub.
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
import re
LINE = re.compile(r"(?P<date>\d{4}-\d{2}-\d{2}) (?P<level>[A-Z]+) (?P<message>.+)")
def parse_log_line(line: str) -> dict[str, str] | None:
found = LINE.fullmatch(line)
if found is None:
return None
return found.groupdict()
def iso_to_german(text: str) -> str:
return re.sub(r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})", r"\g<day>.\g<month>.\g<year>", text)
if __name__ == "__main__":
print(parse_log_line("2026-09-28 ERROR disk full"))
print(iso_to_german("Due 2026-09-30."))
Installieren Sie Python 3.14 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.py
import re
def parse_log_line(line: str) -> dict[str, str] | None:
# Match the whole line with named groups date, level and message.
return None
def iso_to_german(text: str) -> str:
# Rewrite every 2026-09-30 as 30.09.2026.
return text
if __name__ == "__main__":
print(parse_log_line("2026-09-28 ERROR disk full"))
print(iso_to_german("Due 2026-09-30."))
test_main.py
from main import iso_to_german, parse_log_line
def test_parse():
"""Eine Logzeile wird ein dict mit date, level und message"""
got = parse_log_line("2026-09-28 ERROR disk full on /dev/sda1")
want = {"date": "2026-09-28", "level": "ERROR", "message": "disk full on /dev/sda1"}
assert got == want, f"parse_log_line gab {got!r} zurück"
def test_reject():
"""Zeilen, die nicht passen, ergeben None"""
lines = ["2026-09-28 error disk full", "2026-09-28 INFO", "x 2026-09-28 INFO hi"]
got = [parse_log_line(line) for line in lines]
assert got == [None, None, None], f"für {lines!r} gab parse_log_line {got!r} zurück"
def test_german_dates():
"""Jedes Datum wird als Tag.Monat.Jahr geschrieben"""
got = iso_to_german("from 2026-09-01 to 2026-09-30")
assert got == "from 01.09.2026 to 30.09.2026", f"iso_to_german gab {got!r} zurück"
def test_no_dates():
"""Text ohne Datum bleibt gleich"""
got = iso_to_german("no dates here")
assert got == "no dates here", f"iso_to_german gab {got!r} zurück"
Unter macOS und Linux tippen Sie python3, wo in diesen Befehlen python steht, wie in der ersten Lektion.
Programm ausführen:
python main.pyPrüfungen ausführen (learnrun.py muss im selben Ordner liegen):
python learnrun.py testlearnrun.py herunterladenimport re
found = re.match(r"\d+", "Order 42")
print(found.group())
Was Python ausgibt
AttributeError: 'NoneType' object has no attribute 'group'Warum, und die Lösung
match, search und fullmatch liefern None, wenn nichts passt, und None hat kein group(). Hier scheitert match, weil der String mit einem Buchstaben beginnt; search fände 42. Prüfen Sie immer mit if found is None:, bevor Sie Gruppen lesen.
import re
price = re.compile(r"(\d+\.\d{2}")
Was Python ausgibt
re.PatternError: missing ), unterminated subpattern at position 0Warum, und die Lösung
Jede ( einer Gruppe braucht ihre ). Die Position zeigt, wo die offene Gruppe beginnt. Eine echte Klammer finden Sie mit Backslash: r"\(" und r"\)".
import re
found = re.search(r"(?P<year>\d{4})-(?P<month>\d{2})", "due 2026-09")
print(found.group("day"))
Was Python ausgibt
IndexError: no such groupWarum, und die Lösung
Das Muster benennt nur year und month, eine Gruppe day gibt es nicht. Vergleichen Sie die Namen in (?P<...>) mit denen, die Sie lesen. Nummerierte Gruppen zählen die öffnenden Klammern von links, ab 1; Gruppe 0 ist der ganze Treffer.
Python im Browser: Pyodide 314.0.7, MPL-2.0. Lizenz und Quellcode
5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.
Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.