Einführung
Ein regulärer Ausdruck, oder Regex, ist ein mächtiges Werkzeug zur Textverarbeitung. Es handelt sich um eine Zeichenfolge, die ein Suchmuster definiert und es Ihnen ermöglicht, Text mit unglaublicher Flexibilität zu finden, abzugleichen und zu verwalten. In Python wird die Funktionalität für reguläre Ausdrücke durch das Modul re gehandhabt.
In diesem Lab lernen Sie die Grundlagen der Verwendung regulärer Ausdrücke in Python kennen. Wir beginnen mit den Grundlagen des Abgleichens von Mustern und gehen schrittweise zu fortgeschritteneren Themen über, wie Gruppierung, die Verwendung von Quantifizierern für Wiederholungen, die Definition von Zeichenklassen und die Nutzung leistungsstarker Methoden und Flags, um komplexe Abgleichsszenarien zu bewältigen. Am Ende werden Sie sich sicher fühlen, Regex für die Durchführung anspruchsvoller String-Operationen einzusetzen.
Einführung in das Regex Matching
In diesem Schritt lernen Sie den grundlegenden Arbeitsablauf für die Verwendung regulärer Ausdrücke (Regular Expressions, Regex) in Python kennen. Dieser Prozess umfasst typischerweise vier Hauptschritte:
- Importieren des
re-Moduls. - Erstellen eines Regex-Objekts mithilfe von
re.compile(). Die Verwendung eines Raw-Strings (r"...") wird empfohlen, um zu verhindern, dass Backslashes als Escape-Zeichen interpretiert werden. - Verwenden der
search()-Methode des Regex-Objekts, um ein Muster in einem String zu finden. Dies gibt einMatch-Objekt zurück, wenn das Muster gefunden wird. - Verwenden der
group()-Methode desMatch-Objekts, um den tatsächlich gefundenen Text abzurufen.
Zuerst werfen wir einen Blick auf einige gängige Regex-Symbole, die Sie verwenden werden.
| Symbol | Entspricht |
|---|---|
? |
Null oder eine Wiederholung der vorangehenden Gruppe. |
* |
Null oder mehr Wiederholungen der vorangehenden Gruppe. |
+ |
Eine oder mehr Wiederholungen der vorangehenden Gruppe. |
{n} |
Genau n Wiederholungen der vorangehenden Gruppe. |
^spam |
Bedeutet, dass der String mit "spam" beginnen muss. |
spam$ |
Bedeutet, dass der String mit "spam" enden muss. |
. |
Jedes Zeichen außer einem Zeilenumbruch. |
\d, \w, und \s |
Eine Ziffer, ein Wortzeichen bzw. ein Leerzeichen. |
\D, \W, und \S |
Alles außer einer Ziffer, einem Wortzeichen bzw. einem Leerzeichen. |
[abc] |
Jedes Zeichen innerhalb der Klammern (z. B. a, b, c). |
[^abc] |
Jedes Zeichen, das nicht innerhalb der Klammern steht. |
Nun setzen wir dies in die Praxis um. Wir schreiben ein Skript, um eine Telefonnummer in einem String zu finden. Das Muster für eine US-amerikanische Telefonnummer lautet XXX-XXX-XXXX, wobei X eine Ziffer ist. In Regex repräsentiert \d eine Ziffer.
Hinweis: Wenn Sie mit der Verwendung von WebIDE (ähnlich VS Code) nicht vertraut sind, lernen Sie dies bitte zuerst in diesem Lab.
Öffnen Sie die Datei main.py im Dateiexplorer auf der linken Seite und fügen Sie den folgenden Code hinzu.
## Import des re-Moduls für Operationen mit regulären Ausdrücken
import re
## re.compile(): Erstellt ein Regex-Musterobjekt (Raw-String r'' verwenden, um Escaping zu vermeiden)
## Das Muster \d\d\d-\d\d\d-\d\d\d\d passt auf drei Ziffern, einen Bindestrich, drei Ziffern, einen Bindestrich und vier Ziffern.
phone_num_regex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
## Die search()-Methode durchsucht den String und sucht nach der ersten Stelle, an der dieser Regex eine Übereinstimmung ergibt.
mo = phone_num_regex.search('My number is 415-555-4242.')
## Die group()-Methode gibt den String des gefundenen Textes zurück.
print(f'Phone number found: {mo.group()}')
Um das Skript auszuführen, öffnen Sie ein Terminal und führen Sie den folgenden Befehl aus:
python3 main.py
Sie sollten die gefundene Telefonnummer in der Konsole ausgegeben sehen.
Phone number found: 415-555-4242
Dieser grundlegende Arbeitsablauf bildet die Basis für alle Regex-Operationen in Python.
Gruppierung und Alternation
In diesem Schritt lernen Sie, wie Sie spezifische Teile Ihres abgeglichenen Textes mithilfe von Gruppen isolieren und wie Sie mithilfe der Alternation (ODER-Verknüpfung) eines von mehreren möglichen Mustern abgleichen können.
Gruppierung mit Klammern ()
Klammern () werden verwendet, um Gruppen innerhalb eines regulären Ausdrucks zu erstellen. Dies ist nützlich, wenn Sie Teile eines Matches extrahieren möchten, wie z. B. die Vorwahl aus einer Telefonnummer. Sie können auf einzelne Gruppen mit group(n) zugreifen, wobei group(1) die erste Gruppe, group(2) die zweite usw. ist. group(0) oder group() gibt den gesamten abgeglichenen String zurück.
Lassen Sie uns main.py modifizieren, um die Vorwahl vom Rest der Telefonnummer zu trennen.
import re
## Parentheses create groups: group(1) for the first group, group(2) for the second.
## The first group (\d\d\d) captures the area code.
## The second group (\d\d\d-\d\d\d\d) captures the main number.
phone_num_regex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
mo = phone_num_regex.search('My number is 415-555-4242.')
## To retrieve all groups at once, use the groups() method, which returns a tuple.
area_code, main_number = mo.groups()
print(f"Area Code: {area_code}")
print(f"Main Number: {main_number}")
print(f"Full Match: {mo.group(0)}")
Führen Sie das Skript aus:
python3 main.py
Die Ausgabe zeigt die getrennten Teile der Nummer:
Area Code: 415
Main Number: 555-4242
Full Match: 415-555-4242
Alternation mit dem Pipe-Zeichen |
Das Pipe-Zeichen | fungiert als "ODER"-Operator. Es ermöglicht Ihnen, eines von mehreren Ausdrücken abzugleichen. Zum Beispiel gleicht Batman|Tina Fey entweder "Batman" oder "Tina Fey" ab.
Sie können das Pipe-Zeichen auch innerhalb einer Gruppe verwenden, um eines von mehreren möglichen Mustern als Teil Ihres Regex abzugleichen. Versuchen wir, verschiedene "Bat-" bezogene Begriffe abzugleichen. Aktualisieren Sie Ihre main.py mit dem folgenden Code:
import re
## The pipe | matches one of several patterns within a group.
## Here, it matches 'man', 'mobile', 'copter', or 'bat'.
bat_regex = re.compile(r'Bat(man|mobile|copter|bat)')
mo = bat_regex.search('Batmobile lost a wheel')
print(f"Full match: {mo.group()}")
print(f"Group 1: {mo.group(1)}")
Führen Sie das Skript erneut aus:
python3 main.py
Sie werden sehen, dass der Regex "Batmobile" abgeglichen hat und die erste Gruppe "mobile" erfasst hat.
Full match: Batmobile
Group 1: mobile
Wiederholung mit Quantifizierern
In diesem Schritt untersuchen wir Quantifizierer, spezielle Zeichen, mit denen Sie angeben können, wie oft eine vorhergehende Gruppe wiederholt werden soll.
Optionales Matching mit ?
Das Fragezeichen ? macht die vorhergehende Gruppe optional, was bedeutet, dass sie null oder einmal abgeglichen wird. Dies ist ideal für Muster, die möglicherweise vorhanden sind oder auch nicht. Wir können zum Beispiel sowohl "Batman" als auch "Batwoman" abgleichen.
Aktualisieren Sie main.py mit diesem Code:
import re
## The (wo)? group is optional. It will match 'wo' if it exists, or match nothing if it doesn't.
bat_regex = re.compile(r'Bat(wo)?man')
mo1 = bat_regex.search('The Adventures of Batman')
print(mo1.group())
mo2 = bat_regex.search('The Adventures of Batwoman')
print(mo2.group())
Führen Sie das Skript aus:
python3 main.py
Die Ausgabe zeigt, dass beide Strings erfolgreich abgeglichen wurden:
Batman
Batwoman
Null oder mehr mit *
Der Stern * (oder Sternchen) gleicht die vorhergehende Gruppe null oder mehrmals ab. Dies ist nützlich, wenn ein Muster beliebig oft wiederholt werden kann, einschließlich gar nicht.
import re
## The (wo)* group can appear zero or more times.
bat_regex = re.compile(r'Bat(wo)*man')
mo1 = bat_regex.search('The Adventures of Batman') ## Zero 'wo'
print(mo1.group())
mo2 = bat_regex.search('The Adventures of Batwowowowoman') ## Four 'wo's
print(mo2.group())
Eins oder mehr mit +
Das Pluszeichen + gleicht die vorhergehende Gruppe ein- oder mehrmals ab. Im Gegensatz zum Stern muss die Gruppe mindestens einmal vorkommen.
import re
## The (wo)+ group must appear at least once.
bat_regex = re.compile(r'Bat(wo)+man')
mo1 = bat_regex.search('The Adventures of Batwoman') ## One 'wo'
print(mo1.group())
mo2 = bat_regex.search('The Adventures of Batman') ## Zero 'wo's
print(mo2 is None) ## This will print True because no match is found.
Spezifische Wiederholungen mit {}
Geschweifte Klammern {} ermöglichen es Ihnen, eine exakte Anzahl von Wiederholungen oder einen Bereich anzugeben.
{3}gleicht genau dreimal ab.{3,5}gleicht zwischen drei und fünfmal ab.{3,}gleicht dreimal oder öfter ab.{,5}gleicht bis zu fünfmal ab.
import re
## (Ha){3} matches 'Ha' repeated exactly 3 times.
ha_regex = re.compile(r'(Ha){3}')
mo1 = ha_regex.search('HaHaHa')
print(mo1.group())
Gieriges (Greedy) und nicht-gieriges (Non-Greedy) Matching
Standardmäßig ist das Regex von Python "gierig" (greedy), was bedeutet, dass es den längstmöglichen String abgleicht. Um es "nicht-gierig" (non-greedy) zu machen (den kürzestmöglichen String abzugleichen), fügen Sie ein Fragezeichen ? nach dem Quantifizierer hinzu.
Sehen wir uns den Unterschied an. Löschen Sie main.py und fügen Sie Folgendes hinzu:
import re
## Greedy match: {3,5} matches the longest possible string (5 'Ha's).
greedy_ha_regex = re.compile(r'(Ha){3,5}')
mo1 = greedy_ha_regex.search('HaHaHaHaHa')
print(f"Greedy match: {mo1.group()}")
## Non-greedy match: {3,5}? matches the shortest possible string (3 'Ha's).
non_greedy_ha_regex = re.compile(r'(Ha){3,5}?')
mo2 = non_greedy_ha_regex.search('HaHaHaHaHa')
print(f"Non-greedy match: {mo2.group()}")
Führen Sie das Skript aus:
python3 main.py
Die Ausgabe zeigt den Unterschied deutlich:
Greedy match: HaHaHaHaHa
Non-greedy match: HaHaHa
Zeichenklassen, Anker und Wildcards
In diesem Schritt lernen Sie fortgeschrittenere Techniken kennen, einschließlich des Findens aller Übereinstimmungen, des Erstellens benutzerdefinierter Zeichensätze, des Verankerns von Übereinstimmungen am Anfang oder Ende eines Strings und der Verwendung von Platzhaltern.
Die Methode findall()
Während search() nur die erste Übereinstimmung zurückgibt, gibt die Methode findall() eine Liste aller nicht überlappenden Übereinstimmungen im String zurück. Wenn der Regex Gruppen enthält, gibt findall() eine Liste von Tupeln zurück, wobei jedes Tupel die Strings für jede Gruppe enthält.
Aktualisieren Sie main.py mit diesem Beispiel:
import re
## If the regex has no groups, findall() returns a list of strings.
phone_num_regex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
matches = phone_num_regex.findall('Cell: 415-555-9999 Work: 212-555-0000')
print(matches)
Führen Sie das Skript aus, um die Ausgabe zu sehen:
python3 main.py
['415-555-9999', '212-555-0000']
Erstellen eigener Zeichenklassen []
Eckige Klammern [] ermöglichen es Ihnen, eine benutzerdefinierte Zeichenklasse zu definieren, die mit jedem einzelnen Zeichen darin übereinstimmt. Zum Beispiel gleicht [aeiou] jeden Kleinbuchstaben-Vokal ab. Sie können auch einen Bereich angeben, wie [a-z] für jeden Kleinbuchstaben oder [0-9] für jede Ziffer.
Ein Caret ^ als erstes Zeichen innerhalb der Klammern erstellt eine negative Zeichenklasse, die mit jedem Zeichen übereinstimmt, das nicht in der Klasse enthalten ist.
Finden wir alle Vokale in einem String. Aktualisieren Sie main.py:
import re
## [aeiouAEIOU] matches any vowel, lowercase or uppercase.
vowel_regex = re.compile(r'[aeiouAEIOU]')
vowels = vowel_regex.findall('Robocop eats baby food. BABY FOOD.')
print(vowels)
Anker: Caret ^ und Dollarzeichen $
Anker werden verwendet, um eine Position im String zu bestätigen (assert).
- Das Caret
^gleicht den Anfang des Strings ab. - Das Dollarzeichen
$gleicht das Ende des Strings ab.
Wenn sie zusammen verwendet werden (^...$), erzwingen sie, dass der gesamte String mit dem Muster übereinstimmen muss.
import re
## ^Hello matches strings that start with 'Hello'.
begins_with_hello = re.compile(r'^Hello')
match1 = begins_with_hello.search('Hello world!')
print(match1 is not None) ## True
## \d+$ matches strings that end with one or more digits.
ends_with_number = re.compile(r'\d+$')
match2 = ends_with_number.search('Your number is 42')
print(match2.group()) ## '42'
## ^\d+$ matches strings that consist only of digits.
whole_string_is_num = re.compile(r'^\d+$')
match3 = whole_string_is_num.search('1234567890')
print(match3 is not None) ## True
Das Platzhalterzeichen .
Der Punkt . (oder Platzhalter) gleicht jedes einzelne Zeichen außer einem Zeilenumbruch ab. Es ist eine nützliche Abkürzung für "jedes Zeichen".
Finden wir alle drei Buchstaben langen Wörter, die auf "at" enden. Aktualisieren Sie main.py:
import re
## The . character matches any character (except newline).
## So, .at matches 'cat', 'hat', 'sat', etc.
at_regex = re.compile(r'.at')
matches = at_regex.findall('The cat in the hat sat on the flat mat.')
print(matches)
Führen Sie das Skript aus:
python3 main.py
Die Ausgabe ist eine Liste aller abgeglichenen Wörter:
['cat', 'hat', 'sat', 'lat', 'mat']
Erweiterte Methoden und Flags
In diesem letzten Schritt behandeln wir einige leistungsstarke Methoden und Flags, die das Verhalten Ihrer regulären Ausdrücke modifizieren und sie noch vielseitiger machen.
Alles abgleichen mit Punkt-Stern .*
Die Kombination .* ist ein gängiges Muster, das jedes Zeichen (.) null oder mehrmals (*) abgleicht. Es wird verwendet, um jede Zeichensequenz abzugleichen. Standardmäßig ist es gierig (greedy) und gleicht so viel Text wie möglich ab.
import re
## The pattern (.*) captures everything between 'First Name: ' and ' Last Name: '.
name_regex = re.compile(r'First Name: (.*) Last Name: (.*)')
mo = name_regex.search('First Name: Al Last Name: Sweigart')
print(f"First Name: {mo.group(1)}")
print(f"Last Name: {mo.group(2)}")
Um es nicht-gierig (non-greedy) zu machen, verwenden Sie .*?. Dies gleicht den kürzestmöglichen String ab.
Zeilenumbrüche mit re.DOTALL abgleichen
Standardmäßig gleicht das Punktzeichen . keine Zeilenumbruchzeichen (\n) ab. Um dies zu ändern, können Sie re.DOTALL als zweites Argument an re.compile() übergeben. Dieses Flag erlaubt es dem Punkt, alle Zeichen abzugleichen, einschließlich Zeilenumbrüchen.
import re
## With re.DOTALL, '.*' will match across multiple lines.
newline_regex = re.compile('.*', re.DOTALL)
mo = newline_regex.search('Serve the public trust.\nProtect the innocent.\nUphold the law.')
print(mo.group())
Groß-/Kleinschreibung ignorierendes Matching mit re.IGNORECASE
Um Ihren Regex die Groß- und Kleinschreibung ignorieren zu lassen (z. B. "cat", "Cat" und "CAT" abzugleichen), übergeben Sie re.IGNORECASE oder dessen Kurzform re.I als zweites Argument an re.compile().
import re
## re.I makes the pattern 'robocop' match 'Robocop', 'ROBOCOP', etc.
robocop = re.compile(r'robocop', re.I)
match = robocop.search('Robocop is part man, part machine, all cop.')
print(match.group())
Strings ersetzen mit der Methode sub()
Die Methode sub() findet alle Vorkommen eines Musters und ersetzt sie durch einen angegebenen String. Sie benötigt zwei Argumente: den Ersatzstring und den zu durchsuchenden String.
Ersetzen wir Agentennamen durch "CENSORED". Aktualisieren Sie main.py:
import re
## The pattern 'Agent \w+' matches 'Agent ' followed by one or more word characters.
names_regex = re.compile(r'Agent \w+')
result = names_regex.sub('CENSORED', 'Agent Alice gave the secret documents to Agent Bob.')
print(result)
Führen Sie das Skript aus:
python3 main.py
Die Ausgabe zeigt den ersetzten String:
CENSORED gave the secret documents to CENSORED.
Verwaltung komplexer Regexes mit re.VERBOSE
Wenn Regex-Muster komplex werden, können sie schwer lesbar sein. Durch die Übergabe von re.VERBOSE an re.compile() können Sie Ihren Regex über mehrere Zeilen schreiben und Kommentare hinzufügen, um verschiedene Teile zu erklären. Leerzeichen und Kommentare (#) innerhalb des Strings werden ignoriert.
Dieser komplexe Regex:
phone_regex = re.compile(r'((\d{3}|\(\d{3}\))?(\s|-|\.)?\d{3}(\s|-|\.)\d{4}(\s*(ext|x|ext.)\s*\d{2,5})?)')
Wird mit re.VERBOSE zu dieser lesbaren Version:
import re
phone_regex = re.compile(r'''(
(\d{3} | \(\d{3}\))? ## area code (optional)
(\s | - | \.)? ## separator (optional)
\d{3} ## first 3 digits
(\s | - | \.) ## separator
\d{4} ## last 4 digits
(\s*(ext|x|ext.)\s*\d{2,5})? ## extension (optional)
)''', re.VERBOSE)
mo = phone_regex.search("My phone number is 415-555-4242 ext. 55")
if mo:
print(f"Found: {mo.group()}")
Dies macht Ihren Code wesentlich wartbarer.
Zusammenfassung
In diesem Lab haben Sie die Grundlagen regulärer Ausdrücke (Regular Expressions) in Python mithilfe des re-Moduls gemeistert. Sie haben den gesamten Workflow erlernt, vom Kompilieren eines Musters mit re.compile() über das Finden von Übereinstimmungen mit search() bis hin zum Abrufen von Text mit group().
Sie haben wichtige Konzepte erkundet, darunter:
- Gruppierung mit
()zum Erfassen spezifischer Teile einer Übereinstimmung. - Alternation (Oder-Verknüpfung) mit
|zum Abgleichen eines von mehreren Mustern. - Quantifizierer (Quantifiers) wie
?,*,+und{}zur Steuerung der Wiederholungen. - Gieriges vs. Nicht-gieriges Matching zur Steuerung der Länge der Übereinstimmungen.
- Fortgeschrittene Werkzeuge wie
findall()zum Abrufen aller Übereinstimmungen, Zeichenklassen[]für benutzerdefinierte Mengen und Anker^und$zum Fixieren von Übereinstimmungen an String-Grenzen. - Leistungsstarke Flags wie
re.DOTALLfür mehrzeiliges Matching,re.IGNORECASEfür die Ignorierung der Groß-/Kleinschreibung undre.VERBOSEzum Schreiben sauberer, kommentierter Regexes. - String-Ersetzung mit der Methode
sub().
Mit diesen Fähigkeiten sind Sie nun in der Lage, eine Vielzahl von Textverarbeitungsaufgaben zu bewältigen, von einfacher Datenvalidierung bis hin zu komplexer Datenextraktion und -manipulation.



