Python Regex – Wie man den Zeilenanfang (^) und das Zeilenende ($) findet

In diesem Artikel geht es um die regulären Ausdrücke ^ am Zeilenanfang und $ am Zeilenende in der Python-Bibliothek re.
Diese beiden Regexe sind grundlegend für alle regulären Ausdrücke – auch außerhalb der Python-Welt.

Python Start-of-String (^) Regex

Man kann den Caret-Operator ^ verwenden, um den Anfang einer Zeichenkette zu finden. Dies ist zum Beispiel nützlich, wenn man sicherstellen will, dass ein Muster am Anfang einer Zeichenkette gefunden wird.

>>> import re>>> re.findall('^PYTHON', 'PYTHON is fun.')>>> ['PYTHON']
>>>

Die Methode findall(muster, zeichenkette) findet alle Vorkommen des Musters in der Zeichenkette. Das Caret am Anfang des Musters ‚^PYTHON‘ stellt sicher, dass man das Wort Python nur am Anfang der Zeichenkette findet. Im vorherigen Beispiel machte dies keinen Unterschied. Im nächsten Beispiel jedoch schon:

>>> re.findall('^PYTHON', 'PYTHON! PYTHON is fun')
>>> ['PYTHON']
>>>

Obwohl die Teilzeichenkette „PYTHON“ zweimal vorkommt, gibt es nur einen passenden Treffer – am Anfang der Zeichenkette.
Was aber, wenn man nicht nur am Anfang der Zeichenfolge, sondern am Anfang jeder Zeile einer mehrzeiligen Zeichenfolge Übereinstimmungen finden möchte? Mit anderen Worten:

Python Start-of-Line (^) Regex

Der Caret-Operator gilt standardmäßig nur für den Anfang einer Zeichenfolge. Wenn man also eine mehrzeilige Zeichenkette hat, z. B. beim Lesen einer Textdatei, wird er nur einmal angewendet: am Anfang der Zeichenkette.
Es kann jedoch sein, dass man am Anfang jeder Zeile einen Treffer landen will. Man kann z.B. alle Zeilen suchen, die mit „Python“ in einer bestimmten Zeichenfolge beginnen.
Mit dem Flag re.MULTILINE kann man festlegen, dass der Caret-Operator auf den Anfang jeder Zeile angewendet wird. Hier ist ein Beispiel, das beide Verwendungen zeigt – ohne und mit gesetztem re.MULTILINE-Flag:

>>> import re
>>> text = '''
Python is great.
Python is the fastest growing
major programming language in
the world.
Pythonistas thrive.'''
>>> re.findall('^Python', text)
[]
>>> re.findall('^Python', text, re.MULTILINE)
['Python', 'Python', 'Python']
>>> 

Die erste Ausgabe ist die leere Liste, weil die Zeichenfolge „Python“ nicht am Anfang der Zeichenfolge erscheint.
Die zweite Ausgabe ist die Liste der drei übereinstimmenden Teilzeichenketten, weil die Zeichenkette „Python“ dreimal am Anfang einer Zeile vorkommt.

Python re.sub()

Die Methode re.sub(pattern, repl, string, count=0, flags=0) gibt eine neue Zeichenkette zurück, in der alle Vorkommen des Pattern in der alten Zeichenkette durch repl ersetzt werden.
Man kann den Caret-Operator verwenden, um alle Stellen zu ersetzen, an denen ein Pattern am Anfang der Zeichenkette erscheint:

>>> import re
>>> re.sub('^Python', 'Code', 'Python is \nPython')
'Code is \nPython'
>>>

Nur der Anfang der Zeichenkette stimmt mit dem Regex-Muster überein, so dass man nur eine Ersetzung hat.
Auch hier kann man das re.MULTILINE-Flag verwenden, um den Anfang jeder Zeile mit dem Caret-Operator abzugleichen. Damit ersetzt man beide Vorkommen der Zeichenkette ‚Python‘.

>>> import re
>>> re.sub('^Python', 'Code', 'Python is \nPython', flags=re.MULTILINE)
'Code is \nCode'
>>> 

Python re.match(), re.search(), re.findall(), and re.fullmatch()

Lasst uns kurz die wichtigsten Regex-Methoden in Python rekapitulieren:

  • Die Methode re.findall(pattern, string, flags=0) gibt eine Liste von String-Treffern zurück.
  • Die Methode re.search(pattern, string, flags=0) gibt ein Match-Objekt der ersten Übereinstimmung zurück.
  • Die Methode re.match(pattern, string, flags=0) gibt ein match-Objekt zurück, wenn die Regex am Anfang der Zeichenkette übereinstimmt.
  • Die Methode re.fullmatch(pattern, string, flags=0) gibt ein Match-Objekt zurück, wenn die Regex auf die gesamte Zeichenkette passt.

Man sieht, dass alle vier Methoden nach einem Muster in einer gegebenen Zeichenkette suchen. Man kann den Caret-Operator ^ in jedem Pattern verwenden, um den Anfang der Zeichenkette zu finden.

>>> import re
>>> text = 'Python is Python'
>>> re.findall('^Python', text)
['Python']
>>> re.search('^Python', text)
<re.Match object; span=(0, 6), match='Python'>
>>> re.match('^Python', text)
<re.Match object; span=(0, 6), match='Python'>
>>> re.fullmatch('^Python', text)
>>>

Man kann also den Caret-Operator verwenden, um am Anfang der Zeichenkette zu suchen. Man sollte jedoch beachten, dass es nicht sehr sinnvoll ist, ihn für die Methoden match() und fullmatch() zu verwenden, da diese per Definition zunächst versuchen, das erste Zeichen der Zeichenkette zu finden.

Man kann auch das re.MULTILINE-Flag verwenden, um den Anfang jeder Zeile abzugleichen (und nicht nur den Anfang der Zeichenkette):

>>> import re
>>> text = '''Python is
Python'''
>>> re.findall('^Python', text, flags=re.MULTILINE)
['Python', 'Python']
>>> re.search('^Python', text, flags=re.MULTILINE)
<re.Match object; span=(0, 6), match='Python'>
>>> re.match('^Python', text, flags=re.MULTILINE)
<re.Match object; span=(0, 6), match='Python'>
>>> re.fullmatch('^Python', text, flags=re.MULTILINE)
>>>

Python End-of-String ($) Regex

In ähnlicher Weise kann man den Dollar-Zeichen-Operator $ verwenden, um das Ende der Zeichenkette zu finden.

>>> import re
>>> re.findall('fun$', 'PYTHON is fun')
['fun']
>>> 

Die findall()-Methode findet alle Vorkommen des Musters in der Zeichenkette – obwohl das nachgestellte Dollarzeichen $ sicherstellt, dass die Regex nur am Ende der Zeichenkette passt.
Dies kann die Bedeutung des Regex erheblich verändern, wie man im nächsten Beispiel sehen kann:

>>> import re
>>> re.findall('fun$', 'fun fun fun')
['fun']
>>> 

Obwohl die Teilzeichenkette „fun“ dreimal vorkommt, gibt es nur einen passenden Treffer – am Ende der Zeichenkette.
Was aber, wenn man nicht nur am Ende der Zeichenkette, sondern am Ende jeder Zeile in einer mehrzeiligen Zeichenkette Übereinstimmungen finden möchten?

Python End-of-Line ($) Regex

Der Dollar-Zeichen-Operator gilt standardmäßig nur für das Ende einer Zeichenfolge. Wenn man also eine mehrzeilige Zeichenkette hat, z. B. beim Lesen einer Textdatei, wird er trotzdem nur einmal angewendet: am Ende der Zeichenkette.
Es kann jedoch sein, dass man am Ende jeder Zeile einen Treffer erzielen möchte. Man möchte z.B. alle Zeilen finden, die mit „.py“ enden.
Um dies zu erreichen, kann man mit dem re.MULTILINE-Flag festlegen, dass der Dollarzeichen-Operator am Ende jeder Zeile gesucht wird. Hier ist ein Beispiel, das beide Verwendungen zeigt – ohne und mit gesetztem re.MULTILINE-Flag:

>>> import re
>>> text = '''
Coding is fun
Python is fun
Games are fun
Agreed?'''
>>> re.findall('fun$', text)
[]
>>> re.findall('fun$', text, flags=re.MULTILINE)
['fun', 'fun', 'fun']
>>>

Die erste Ausgabe ist die leere Liste, da die Zeichenfolge „fun“ nicht am Ende der Zeichenfolge erscheint.
Die zweite Ausgabe ist die Liste der drei übereinstimmenden Teilzeichenketten, da die Zeichenfolge „fun“ dreimal am Ende einer Zeile vorkommt.

Python re.sub()

Die Methode re.sub(pattern, repl, string, count=0, flags=0) gibt eine neue Zeichenkette zurück, bei der alle Vorkommen des Pattern in der alten Zeichenkette durch repl ersetzt werden.
Man kann den Dollar-Zeichen-Operator verwenden, um überall dort zu ersetzen, wo ein Muster am Ende der Zeichenkette erscheint:

>>> import re
>>> re.sub('Python$', 'Code', 'Is Python\nPython')
'Is Python\nCode'
>>> 

Nur das Ende der Zeichenkette stimmt mit dem Regex-Muster überein, so dass es nur eine Ersetzung gibt.
Auch hier kann man das Flag re.MULTILINE verwenden, um das Ende jeder Zeile mit dem Dollar-Zeichen-Operator abzugleichen:

>>> import re
>>> re.sub('Python$', 'Code', 'Is Python\nPython', flags=re.MULTILINE)
'Is Code\nCode'
>>>

Python re.match(), re.search(), re.findall(), and re.fullmatch()

Alle vier Methoden – re.findall(), re.search(), re.match() und re.fullmatch() – suchen nach einem Muster in einer bestimmten Zeichenkette. Man kann den Dollar-Zeichen-Operator $ innerhalb jedes Musters verwenden, um das Ende der Zeichenkette zu finden.

>>> import re
>>> text = 'Python is Python'
>>> re.findall('Python$', text)
['Python']
>>> re.search('Python$', text)
<re.Match object; span=(10, 16), match='Python'>
>>> re.match('Python$', text)
>>> re.fullmatch('Python$', text)
>>>

Man kann also den Dollar-Zeichen-Operator verwenden, um am Ende der Zeichenkette zu suchen. Man sollte jedoch beachten, dass es nicht sehr sinnvoll ist, diesen Operator für die fullmatch()-Methoden zu verwenden, da er bereits per Definition voraussetzt, dass das letzte Zeichen der Zeichenkette Teil der passenden Teilzeichenkette ist.
Man kann auch das re.MULTILINE-Flag verwenden, um das Ende jeder Zeile abzugleichen (und nicht nur das Ende der gesamten Zeichenkette):

>>> import re
>>> text = '''Is Python
Python'''
>>> re.findall('Python$', text, flags=re.MULTILINE)
['Python', 'Python']
>>> re.search('Python$', text, flags=re.MULTILINE)
<re.Match object; span=(3, 9), match='Python'>
>>> re.match('Python$', text, flags=re.MULTILINE)
>>> re.fullmatch('Python$', text, flags=re.MULTILINE)
>>>

Da das Muster nicht mit dem String-Präfix übereinstimmt, liefern sowohl re.match() als auch re.fullmatch() leere Ergebnisse.

Wie kann man das Caret (^) oder Dollar ($) Symbol mit einer Regex suchen?

Man weiß, dass die Caret- und Dollar-Symbole in Python für reguläre Ausdrücke eine besondere Bedeutung haben: Sie passen auf den Anfang oder das Ende jeder Zeichenkette/Zeile. Aber was ist, wenn man nach dem Caret- (^) oder Dollar-Symbol ($) selbst suchen möchte? Wie kann man sie in einer Zeichenkette finden?

Die Antwort ist einfach: Die Caret- oder Dollar-Symbole werden in Ihrem regulären Ausdruck mit einem Backslash getrennt. Man verwendet insbesondere ‚\^‘ anstelle von ‚^‘ und ‚\$‘ anstelle von ‚$‘.
Durch das Escapen der Sonderzeichen ^ und $ weist man die Regex-Engine an, ihre besondere Bedeutung zu ignorieren.