re

Die Python-Standard-Bibliothek re enthält ebenfalls Funktionen für die Arbeit mit Zeichenketten. Dabei bietet re ausgefeiltere Möglichkeiten zur Musterextraktion und -ersetzung als der str-Typ.

>>> import re
>>> re.sub("\n", "", welcome)
'Hello pythonistas!'

Hier wird der reguläre Ausdruck zunächst kompiliert und dann seine re.Pattern.sub()-Methode für den übergebenen Text aufgerufen. Ihr könnt den Ausdruck selbst mit re.compile() kompilieren und so ein wiederverwendbares regex-Objekt bilden, das auf unterschiedliche Zeichenketten angewendet die CPU-Zyklen verringert:

>>> regex = re.compile("\n")
>>> regex.sub("", welcome)
'Hello pythonistas!'

Wenn ihr stattdessen eine Liste aller Muster erhalten möchtet, die dem regex-Objekt entsprechen, könnt ihr die re.Pattern.findall()-Methode verwenden:

>>> regex.findall(welcome)
['\n']

Bemerkung

Um das umständliche Escaping mit \ in einem regulären Ausdruck zu vermeiden, könnt ihr rohe String-Literale wie r'C:\PATH\TO\FILE' anstelle des entsprechenden 'C:\\PATH\\TO\\FILE' verwenden.

re.Pattern.match() und re.Pattern.search() sind eng mit re.Pattern.findall() verwandt. Während findall alle Übereinstimmungen in einer Zeichenkette zurückgibt, gibt search nur die erste Übereinstimmung und match nur Übereinstimmungen am Anfang der Zeichenkette zurück. Als weniger triviales Beispiel betrachten wir einen Textblock und einen regulären Ausdruck, der die meisten E-Mail-Adressen identifizieren kann:

>>> addresses = """Veit <veit@cusy.io>
... Veit Schiele <veit.schiele@cusy.io>
... cusy GmbH <info@cusy.io>
... """
>>> pattern = r"[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}"
>>> regex = re.compile(pattern, flags=re.IGNORECASE)
>>> regex.findall(addresses)
['veit@cusy.io', 'veit.schiele@cusy.io', 'info@cusy.io']
>>> regex.search(addresses)
<re.Match object; span=(6, 18), match='veit@cusy.io'>
>>> print(regex.match(addresses))
None

regex.match gibt None zurück, da das Muster nur dann passt, wenn es am Anfang der Zeichenkette steht.

Angenommen, ihr möchtet E-Mail-Adressen finden und gleichzeitig jede Adresse in ihre drei Komponenten aufteilen:

  1. Personen-Name

  2. Domänen-Name

  3. Domänen-Suffix

Dazu setzt ihr zunächst runde Klammern () um die zu segmentierenden Teile des Musters:

>>> pattern = r"([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})"
>>> regex = re.compile(pattern, flags=re.IGNORECASE)
>>> match = regex.match("veit@cusy.io")
>>> match.groups()
('veit', 'cusy', 'io')

re.Match.groups() gibt ein Tupel zurück, das alle Untergruppen der Übereinstimmung enthält.

re.Pattern.findall() gibt eine Liste von Tupeln zurück, wenn das Muster Gruppen enthält:

>>> regex.findall(addresses)
[('veit', 'cusy', 'io'), ('veit.schiele', 'cusy', 'io'), ('info', 'cusy', 'io')]

Auch in re.Pattern.sub() können Gruppen verwendet werden wobei \1 für die erste übereinstimmende Gruppe steht, \2 für die zweite usw.:

>>> regex.findall(addresses)
[('veit', 'cusy', 'io'), ('veit.schiele', 'cusy', 'io'), ('info', 'cusy', 'io')]
>>> print(regex.sub(r"Username: \1, Domain: \2, Suffix: \3", addresses))
Veit <Username: veit, Domain: cusy, Suffix: io>
Veit Schiele <Username: veit.schiele, Domain: cusy, Suffix: io>
cusy GmbH <Username: info, Domain: cusy, Suffix: io>

Die folgende Tabelle enthält einen kurzen Überblick über Methoden für reguläre Ausdrücke:

Methode

Beschreibung

re.findall()

gibt alle sich nicht überschneidenden übereinstimmenden Muster in einer Zeichenkette als Liste zurück.

re.finditer()

wie findall, gibt aber einen Iterator zurück.

re.match()

entspricht dem Muster am Anfang der Zeichenkette und segmentiert optional die Musterkomponenten in Gruppen; wenn das Muster übereinstimmt, wird ein match-Objekt zurückgegeben, andernfalls keines.

re.search()

durchsucht die Zeichenkette nach Übereinstimmungen mit dem Muster; gibt in diesem Fall ein match-Objekt zurück; im Gegensatz zu match kann die Übereinstimmung an einer beliebigen Stelle der Zeichenkette und nicht nur am Anfang stehen.

re.split()

zerlegt die Zeichenkette bei jedem Auftreten des Musters in Teile.

re.sub(), re.subn()

ersetzt alle (sub) oder die ersten n Vorkommen (subn) des Musters in der Zeichenkette durch einen Ersetzungsausdruck; verwendet die Symbole \1, \2, …, um auf die Elemente der Übereinstimmungsgruppe zu verweisen.

str.removeprefix() str.removesuffix()

In Python 3.9 kann dies verwendet werden, um das Suffix oder den Dateinamen zu extrahieren.

Checks

  • Welchen regulären Ausdruck würdet ihr verwenden, um Zeichenfolgen zu finden, die die Zahlen zwischen -3 und +3 darstellen?

  • Welchen regulären Ausdruck würdet ihr verwenden, um Hexadezimalwerte zu finden?