Mithilfe von regulären Ausdrücken (oder kurz Regex) kannst du maschinell Textstellen aus einem Text finden, bestimmte Zahl in einer Datei auslesen, die Textausgabe eines Kommandozeilentools weiterverarbeiten und einen String auf korrekte Syntax überprüfen.
Reguläre Ausdrücke haben sich in der Informatik längst als Industriestandard etabliert. Sie helfen beim automatischen Auswerten von jeder Form von Strings. Dabei handelt es sich um Schablonen bzw. Templates. Anhand dieser Templates können Substrings in einem größeren Text gefunden werden.
In diesem Tutorial stelle ich die Funktionsweise von regulären Ausdrücken in der Programmiersprache Python vor und zeige dir, wie du sie verwendest.
Was ist ein regulärer Ausdruck
Einen regulären Ausdruck kannst du dir als Suchfilter für eine Textsuche vorstellen. Anders als bei einer statischen Textsuche kannst du mit einem regulären Ausdruck darüber hinaus auch nach Textmustern suchen.
Dieser Ausdruck
^ERROR.*$
angewendet auf diesen Text:
ERROR First error
WARNING First warning
ERROR Second error
INFO first info
INFO second info
WARNING second warning
findet alle Zeilen mit den Zeichen “ERROR”:
ERROR First error
ERROR Second error
Eine einfache Suche nach dem Wort “ERROR” hätte hingegen nur einzelne Wörter gefunden, keine ganzen Zeilen… Regex ist aber noch viel mächtiger als das. Dazu später mehr.
Hallo Welt
Um reguläre Ausdrücke in Python zu verwenden, kannst du das re Modul importieren. Es wird mit der normalen Python 3 Installation mitinstalliert. Deswegen kannst du es ohne vorherige Installation importieren:
import re
text = "Hallo Welt 1, Moin Welt 2, Mahlzeit Welt 3, Servus Welt 4, Ahoi Welt 5"
regex = "\w* Welt 4"
print("Alle Funde:",re.findall(regex,text))
Output:
['Servus Welt 4']
Oder wenn du nicht den ganzen Text durchsuchen willst, weil dir das erste Ergebnis reicht, kannst du auch re.search verwenden:
match = re.search(regex,text)
print("Erstes Match:",match.group(0))
Output:
'Servus Welt 4'
Spezielle Notation
Wie du im Beispiel gesehen hast, musst du bei regulären Ausdrücken auf eine spezielle Notation zurückgreifen. Bestimmte Zeichen bzw. Zeichenkombinationen matchen nicht die Zeichen selbst, sondern haben eine spezielle Bedeutung.
\w steht zum Beispiel für jedes beliebige Wort. Genauer gesagt steht es für die Zeichen von a-z, von A-Z, von 0-9 sowie dem Unterstrich (_).
Character sets
Wenn du nur nach Wörtern mit bestimmten Buchstaben suchen willst, kannst du die Notation mit eckiger Klammer verwenden. Dadurch wird ein sogenanntes “Character set” erzeugt:
import re
text = "Haus Igel Maus MMMMaus Drache aus Sau Pferd"
regex = "[HM]aus"
print("Alle Funde mit nur einem Anfangsbuchstaben:",re.findall(regex,text))
regex = "[HM]+aus"
print("Alle Funde mit mehreren Anfangsbuchstaben:",re.findall(regex,text))
regex = "[HM]*aus"
print("Alle Funde mit mehreren oder keinen Anfangsbuchstaben:",re.findall(regex,text))
Output:
Alle Funde mit nur einem Anfangsbuchstaben: ['Haus', 'Maus', 'Maus']
Alle Funde mit mehreren Anfangsbuchstaben: ['Haus', 'Maus', 'MMMMaus']
Alle Funde mit mehreren oder keinen Anfangsbuchstaben: ['Haus', 'Maus', 'MMMMaus', 'aus']
Das +
bedeutet, dass die Zeichen in der Klammer mindestens einmal vorkommen müssen, aber auch mehrmals vorkommen dürfen. Wenn du stattdessen ein *
schreibst, darf es auch keinmal vorkommen.
Zum Verständnis: Anstelle von \w
kannst du auch [a-zA-Z0-9_]
schreiben. Es hat dieselbe Bedeutung.
Escaping
Da die Klammer eine spezielle Bedeutung hat, kannst du nicht direkt nach dem Klammersymbol [
bzw. ]
suchen. Um das zu bewerkstelligen, musst du es mit einem Backslash \
wie folgt escapen:
import re
text = "Es war einmal [vor langer Zeit]."
regex = r'\[.*]'
print("Ergebnis:",re.search(regex,text).group(0))
Output:
Ergebnis: [vor langer Zeit]
Achte darauf, dass du raw Strings verwendest. Die normalen Pythonstrings nutzen den Backslash nämlich ebenfalls für spezielle Bedeutungen.
Der Punkt .
steht für jeden beliebigen Buchstaben. Dementsprechend müsstest du auch Punkte escapen, wenn du nach ihnen suchen wolltest.
Andere Zeichen die escaped werden müssen sind:
`. ^ $ * + - ? ( ) [ ] { } \ |`
Wenn es dir zu kompliziert wird, kannst du auch einfach die Python eigene re.escape Funktion verwenden.
Was diese Symbole bedeuten kannst du in der offiziellen Dokumentation erfahren.
Sonstige spezielle Zeichen
Hier ein paar weitere spezielle Zeichen die ich oft verwende:
Zeichen | Bedeutung |
---|---|
. | Steht für jedes Zeichen |
^ | Start einer Zeile |
$ | Ende einer Zeile |
* | 0 oder mehr Wiederholungen von vorangegangen Zeichen oder Set |
+ | 1 oder mehr Wiederholungen von vorangegangen Zeichen oder Set |
? | 0 oder 1 Wiederholungen von vorangegangenen Zeichen oder Set |
{m} | genau m Wiederholungen von vorangegangenen Zeichen oder Set |
\ | Escaped ein Zeichen |
[] | definiert ein Set |
\d | steht für Zahlen, wie [0-9] |
\s | Alle Whitespaces (Tabs, Leertasten, Zeilenumbrüche usw.) |
\S | Alles was kein Whitespace ist (Gegenteil von \s) |
\w | Buchstaben die in Wörtern vorkommen, bei ASCII wie [a-zA-Z0-9_] |
\S | Alles was kein Whitespace ist (Gegenteil von \s) |
\b | Markiert den Anfang oder das Ende eines Wortes |
Regex Gruppensuche
Mithilfe von Gruppen kannst du Teile der Suchergebnisse direkt einer Variable zuweisen. Das ist vor allem bei großen und komplexen Texten sinnvoll.
Eine Gruppe ist ein Teil eines Regex Pattern, das in runden Klammern eingeschlossen ist. Wenn du also Teile deines Patterns gruppieren möchtest, kannst du einfach Klammern um den Teil setzen.
Folgender Regex findet zwei aufeinanderfolgende großgeschriebene Worte:
import re
text = "Es war einmal und IST nicht mehr ein AUSGESTOPFTER TEDDYBAER. Er riss sich arm und Beine aus und fuhr sofort ins Krankenhaus."
regex = r"(\b[A-Z]+\b) (\b[A-Z]+\b)"
result = re.search(regex, text)
print(result.groups())
print(result.group(1))
print(result.group(2))
('AUSGESTOPFTER', 'TEDDYBAER')
AUSGESTOPFTER
TEDDYBAER
Nützliche Anwendungsbeispiele
Zu guter Letzt möchte ich dir noch ein paar nützliche Reguläre Ausdrücke mit auf dem Weg geben, die immer wieder nützlich werden können.
IP-Adressen validieren:
^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$
Passwortüberprüfung (8 Zeichen, mindestens ein Großbuchstabe, mindestens ein kleiner Buchstabe, eine Zahl und ein Symbol):
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*\W).{8,}$
E-Mail Format Prüfung:
^[a-zA-Z0-9.!#$%&’*+=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+$
Links
Regex Online ausprobieren: https://regex101.com/ (beachte, dass die Formatierung in Python manchmal etwas anders ist wenn du Zeichen Escapen musst!)
Regex Python Doku https://docs.python.org/3/library/re.html
Konnte ich helfen? Ich freue mich über einen Drink!
💙