Python Language
Reguläre Ausdrücke (Regex)
Suche…
Einführung
Python macht reguläre Ausdrücke über das re
Modul verfügbar.
Reguläre Ausdrücke sind Kombinationen von Zeichen, die als Regeln für übereinstimmende Teilzeichenfolgen interpretiert werden. Zum Beispiel kann der Ausdruck 'amount\D+\d+'
werde jede Saite durch das Wort zusammengesetzt übereinstimmen amount
zuzüglich einer ganzen Zahl, getrennt durch eine oder mehr nicht-Ziffern, wie beispielsweise: amount=100
, amount is 3
, amount is equal to: 33
usw.
Syntax
Direkte reguläre Ausdrücke
re.match (Muster, Zeichenfolge, Flag = 0) # Out: Suchmuster am Anfang der Zeichenfolge oder Keine
re.search (Muster, Zeichenfolge, Flag = 0) # Out: Suchmuster in Zeichenfolge oder Keine
re.findall (Muster, Zeichenfolge, Flag = 0) # Out: Liste aller Übereinstimmungen von Muster in Zeichenfolge oder []
re.finditer (pattern, string, flag = 0) # Out: wie re.findall, gibt jedoch das Iterator-Objekt zurück
re.sub (Muster, Ersetzung, Zeichenfolge, Flag = 0) # Out: Zeichenfolge mit Ersetzung (Zeichenfolge oder Funktion) anstelle von Muster
Vorkompilierte reguläre Ausdrücke
precompiled_pattern = re.compile (Muster, Flag = 0)
precompiled_pattern.match (string) # Out: Übereinstimmung am Anfang von String oder None
precompiled_pattern.search (string) # Out: Entsprechung an beliebiger Stelle in String oder None
precompiled_pattern.findall (string) # Out: Liste aller übereinstimmenden Teilstrings
precompiled_pattern.sub (string / pattern / function, string) # Out: ersetzter String
Den Anfang einer Zeichenfolge abgleichen
Das erste Argument von re.match()
ist der reguläre Ausdruck, das zweite ist der zu re.match()
String:
import re
pattern = r"123"
string = "123zzb"
re.match(pattern, string)
# Out: <_sre.SRE_Match object; span=(0, 3), match='123'>
match = re.match(pattern, string)
match.group()
# Out: '123'
Möglicherweise stellen Sie fest, dass die Mustervariable eine Zeichenfolge mit dem Präfix r
, was darauf hinweist, dass es sich bei der Zeichenfolge um ein reines Zeichenkettenliteral handelt .
Ein Roh-String-Literal hat eine etwas andere Syntax als ein String-Literal, nämlich ein Backslash \
in einem Roh-String-Literal bedeutet "nur ein Backslash", und es ist nicht notwendig, Backlashes zu verdoppeln, um "Escape-Sequenzen" wie Zeilenumbrüche ( \n
) zu vermeiden. , Tabs ( \t
), Backspaces ( \
), Formular-Feeds ( \r
) und so weiter. Bei normalen String-Literalen muss jeder Backslash verdoppelt werden, um nicht als Beginn einer Escape-Sequenz zu gelten.
Daher ist r"\n"
eine Zeichenfolge von 2 Zeichen: \
und n
. Regex-Muster verwenden auch umgekehrte Schrägstriche, z. B. bezieht sich \d
auf ein beliebiges Zeichen. Wir können vermeiden, dass wir unsere Strings ( "\\d"
) mit rohen Strings ( r"\d"
) doppelt sichern müssen.
Zum Beispiel:
string = "\\t123zzb" # here the backslash is escaped, so there's no tab, just '\' and 't'
pattern = "\\t123" # this will match \t (escaping the backslash) followed by 123
re.match(pattern, string).group() # no match
re.match(pattern, "\t123zzb").group() # matches '\t123'
pattern = r"\\t123"
re.match(pattern, string).group() # matches '\\t123'
Der Abgleich erfolgt nur am Anfang der Zeichenfolge. Wenn Sie irgendwo re.search
möchten, verwenden re.search
stattdessen re.search
:
match = re.match(r"(123)", "a123zzb")
match is None
# Out: True
match = re.search(r"(123)", "a123zzb")
match.group()
# Out: '123'
Suchen
pattern = r"(your base)"
sentence = "All your base are belong to us."
match = re.search(pattern, sentence)
match.group(1)
# Out: 'your base'
match = re.search(r"(belong.*)", sentence)
match.group(1)
# Out: 'belong to us.'
Die Suche wird im Gegensatz zu re.match
beliebigen Stelle in der Zeichenfolge re.match
. Sie können auch re.findall
.
Sie können auch am Anfang der Zeichenfolge suchen (verwenden Sie ^
).
match = re.search(r"^123", "123zzb")
match.group(0)
# Out: '123'
match = re.search(r"^123", "a123zzb")
match is None
# Out: True
am Ende des Strings (verwende $
),
match = re.search(r"123$", "zzb123")
match.group(0)
# Out: '123'
match = re.search(r"123$", "123zzb")
match is None
# Out: True
oder beides (verwende sowohl ^
als auch $
):
match = re.search(r"^123$", "123")
match.group(0)
# Out: '123'
Gruppierung
Die Gruppierung erfolgt in Klammern. Beim Aufruf von group()
eine Zeichenfolge zurückgegeben, die aus den übereinstimmenden, in Klammern stehenden Untergruppen besteht.
match.group() # Group without argument returns the entire match found
# Out: '123'
match.group(0) # Specifying 0 gives the same result as specifying no argument
# Out: '123'
Für group()
können auch Argumente bereitgestellt werden, um eine bestimmte Untergruppe abzurufen.
Aus den Dokumenten :
Wenn es ein einzelnes Argument gibt, ist das Ergebnis eine einzelne Zeichenfolge. Wenn es mehrere Argumente gibt, ist das Ergebnis ein Tupel mit einem Element pro Argument.
Wenn Sie groups()
aufrufen, wird dagegen eine Liste von Tupeln zurückgegeben, die die Untergruppen enthalten.
sentence = "This is a phone number 672-123-456-9910"
pattern = r".*(phone).*?([\d-]+)"
match = re.match(pattern, sentence)
match.groups() # The entire match as a list of tuples of the paranthesized subgroups
# Out: ('phone', '672-123-456-9910')
m.group() # The entire match as a string
# Out: 'This is a phone number 672-123-456-9910'
m.group(0) # The entire match as a string
# Out: 'This is a phone number 672-123-456-9910'
m.group(1) # The first parenthesized subgroup.
# Out: 'phone'
m.group(2) # The second parenthesized subgroup.
# Out: '672-123-456-9910'
m.group(1, 2) # Multiple arguments give us a tuple.
# Out: ('phone', '672-123-456-9910')
Benannte Gruppen
match = re.search(r'My name is (?P<name>[A-Za-z ]+)', 'My name is John Smith')
match.group('name')
# Out: 'John Smith'
match.group(1)
# Out: 'John Smith'
Erstellt eine Capture-Gruppe, auf die sowohl nach Name als auch nach Index verwiesen werden kann.
Nicht einfangende Gruppen
Mit (?:)
wird eine Gruppe erstellt, die Gruppe wird jedoch nicht erfasst. Das bedeutet, dass Sie es als Gruppe verwenden können, aber Ihren "Gruppenbereich" nicht verschmutzen.
re.match(r'(\d+)(\+(\d+))?', '11+22').groups()
# Out: ('11', '+22', '22')
re.match(r'(\d+)(?:\+(\d+))?', '11+22').groups()
# Out: ('11', '22')
Dieses Beispiel entspricht 11+22
oder 11
, jedoch nicht 11+
. Das ist , da das +
Zeichen und der zweite Ausdruck gruppiert sind. Auf der anderen Seite, die +
ist Zeichen nicht erfaßt.
Sonderzeichen entkommen
Sonderzeichen (wie die Zeichenklassen [
und ]
unten) werden nicht wörtlich abgeglichen:
match = re.search(r'[b]', 'a[b]c')
match.group()
# Out: 'b'
Durch das Umgehen der Sonderzeichen können sie wörtlich abgeglichen werden:
match = re.search(r'\[b\]', 'a[b]c')
match.group()
# Out: '[b]'
Die Funktion re.escape()
kann für Sie verwendet werden:
re.escape('a[b]c')
# Out: 'a\\[b\\]c'
match = re.search(re.escape('a[b]c'), 'a[b]c')
match.group()
# Out: 'a[b]c'
Die Funktion re.escape()
entgeht allen Sonderzeichen. Sie können also einen regulären Ausdruck basierend auf Benutzereingaben erstellen:
username = 'A.C.' # suppose this came from the user
re.findall(r'Hi {}!'.format(username), 'Hi A.C.! Hi ABCD!')
# Out: ['Hi A.C.!', 'Hi ABCD!']
re.findall(r'Hi {}!'.format(re.escape(username)), 'Hi A.C.! Hi ABCD!')
# Out: ['Hi A.C.!']
Ersetzen
re.sub
können Saiten mit re.sub
.
Zeichenketten ersetzen
re.sub(r"t[0-9][0-9]", "foo", "my name t13 is t44 what t99 ever t44")
# Out: 'my name foo is foo what foo ever foo'
Gruppenreferenzen verwenden
Ersetzungen mit einer kleinen Anzahl von Gruppen können wie folgt durchgeführt werden:
re.sub(r"t([0-9])([0-9])", r"t\2\1", "t13 t19 t81 t25")
# Out: 't31 t91 t18 t52'
Wenn Sie jedoch eine Gruppen-ID wie '10' erstellen, funktioniert dies nicht : \10
wird als 'ID-Nummer 1 gefolgt von 0' gelesen. Sie müssen also genauer sein und die Schreibweise \g<i>
verwenden:
re.sub(r"t([0-9])([0-9])", r"t\g<2>\g<1>", "t13 t19 t81 t25")
# Out: 't31 t91 t18 t52'
Ersatzfunktion verwenden
items = ["zero", "one", "two"]
re.sub(r"a\[([0-3])\]", lambda match: items[int(match.group(1))], "Items: a[0], a[1], something, a[2]")
# Out: 'Items: zero, one, something, two'
Alle nicht überlappenden Übereinstimmungen suchen
re.findall(r"[0-9]{2,3}", "some 1 text 12 is 945 here 4445588899")
# Out: ['12', '945', '444', '558', '889']
Beachten Sie, dass das r
vor "[0-9]{2,3}"
Python anweist, den String so zu interpretieren, wie er ist; als "rohe" Zeichenfolge.
Sie können auch re.finditer()
das auf dieselbe Weise wie re.findall()
jedoch einen Iterator mit SRE_Match
Objekten anstelle einer Liste von Strings SRE_Match
:
results = re.finditer(r"([0-9]{2,3})", "some 1 text 12 is 945 here 4445588899")
print(results)
# Out: <callable-iterator object at 0x105245890>
for result in results:
print(result.group(0))
''' Out:
12
945
444
558
889
'''
Vorkompilierte Muster
import re
precompiled_pattern = re.compile(r"(\d+)")
matches = precompiled_pattern.search("The answer is 41!")
matches.group(1)
# Out: 41
matches = precompiled_pattern.search("Or was it 42?")
matches.group(1)
# Out: 42
Durch das Kompilieren eines Musters kann es später in einem Programm wiederverwendet werden. Beachten Sie jedoch, dass Python kürzlich verwendete Ausdrücke ( docs , SO answer ) zwischenspeichert, so dass "Programme, die jeweils nur wenige reguläre Ausdrücke verwenden, sich keine Sorgen um das Kompilieren regulärer Ausdrücke machen müssen" .
import re
precompiled_pattern = re.compile(r"(.*\d+)")
matches = precompiled_pattern.match("The answer is 41!")
print(matches.group(1))
# Out: The answer is 41
matches = precompiled_pattern.match("Or was it 42?")
print(matches.group(1))
# Out: Or was it 42
Es kann mit re.match () verwendet werden.
Auf zulässige Zeichen prüfen
Wenn Sie überprüfen möchten, dass eine Zeichenfolge nur eine bestimmte Menge von Zeichen enthält, in diesem Fall az, AZ und 0-9, können Sie dies folgendermaßen tun:
import re
def is_allowed(string):
characherRegex = re.compile(r'[^a-zA-Z0-9.]')
string = characherRegex.search(string)
return not bool(string)
print (is_allowed("abyzABYZ0099"))
# Out: 'True'
print (is_allowed("#*@#$%^"))
# Out: 'False'
Sie können die Ausdruckszeile auch von [^a-zA-Z0-9.]
[^a-z0-9.]
, um beispielsweise Großbuchstaben zu verbieten.
Teilgutschrift: http://stackoverflow.com/a/1325265/2697955
Zeichenfolge mit regulären Ausdrücken aufteilen
Sie können auch reguläre Ausdrücke verwenden, um eine Zeichenfolge zu teilen. Zum Beispiel,
import re
data = re.split(r'\s+', 'James 94 Samantha 417 Scarlett 74')
print( data )
# Output: ['James', '94', 'Samantha', '417', 'Scarlett', '74']
Flaggen
In einigen speziellen Fällen müssen wir das Verhalten des regulären Ausdrucks ändern. Dies geschieht mithilfe von Flags. Flags können auf zwei Arten gesetzt werden, über das Schlüsselwort flags
oder direkt im Ausdruck.
Flaggen-Schlüsselwort
Nachfolgend ein Beispiel für re.search
aber es funktioniert für die meisten Funktionen im Modul re
.
m = re.search("b", "ABC")
m is None
# Out: True
m = re.search("b", "ABC", flags=re.IGNORECASE)
m.group()
# Out: 'B'
m = re.search("a.b", "A\nBC", flags=re.IGNORECASE)
m is None
# Out: True
m = re.search("a.b", "A\nBC", flags=re.IGNORECASE|re.DOTALL)
m.group()
# Out: 'A\nB'
Gemeinsame Flaggen
Flagge | kurze Beschreibung |
---|---|
re.IGNORECASE , re.I | Lässt das Muster den Fall ignorieren |
re.DOTALL , re.S | Macht . alles zusammenbringen, einschließlich Newlines |
re.MULTILINE , re.M | Lässt ^ den Anfang einer Zeile und $ das Ende einer Zeile anpassen |
re.DEBUG | Aktiviert Debug-Informationen |
Die vollständige Liste aller verfügbaren Flags finden Sie in den Dokumenten
Inline-Flags
Aus den Dokumenten :
(?iLmsux)
(Ein oder mehrere Buchstaben aus der Gruppe 'i', 'L', 'm', 's', 'u', 'x'.)Die Gruppe stimmt mit der leeren Zeichenfolge überein. die Buchstaben setzen die entsprechenden Flags: re.I (Groß- / Kleinschreibung ignorieren), re.L (abhängig vom Gebietsschema), re.M (mehrzeilig), re.S (Punkt trifft auf alle zu), re.U (abhängig von Unicode) und re.X (verbose) für den gesamten regulären Ausdruck. Dies ist nützlich, wenn Sie die Flags als Teil des regulären Ausdrucks einschließen möchten, anstatt ein Flagargument an die Funktion re.compile () zu übergeben.
Beachten Sie, dass das Flag (? X) ändert, wie der Ausdruck analysiert wird. Es sollte zuerst in der Ausdruckszeichenfolge oder nach einem oder mehreren Leerzeichen verwendet werden. Wenn sich vor dem Flag Zeichen ohne Leerzeichen befinden, sind die Ergebnisse undefiniert.
Iteration über Matches mit `re.finditer`
Sie können re.finditer
, um alle Übereinstimmungen in einer Zeichenfolge zu re.finditer
. Dies gibt Ihnen (im Vergleich zu re.findall
zusätzliche Informationen, z. B. Informationen über den Übereinstimmungsort in der Zeichenfolge (Indizes):
import re
text = 'You can try to find an ant in this string'
pattern = 'an?\w' # find 'an' either with or without a following word character
for match in re.finditer(pattern, text):
# Start index of match (integer)
sStart = match.start()
# Final index of match (integer)
sEnd = match.end()
# Complete match (string)
sGroup = match.group()
# Print match
print('Match "{}" found at: [{},{}]'.format(sGroup, sStart,sEnd))
Ergebnis:
Match "an" found at: [5,7]
Match "an" found at: [20,22]
Match "ant" found at: [23,26]
Stimmen Sie einen Ausdruck nur an bestimmten Orten ab
Häufig möchten Sie einen Ausdruck nur an bestimmten Stellen zuordnen (dh, er bleibt an anderen Stellen unberührt). Betrachten Sie den folgenden Satz:
An apple a day keeps the doctor away (I eat an apple everyday).
Hier kommt der "Apfel" zweimal vor, was mit sogenannten Backtracking-Kontrollverben gelöst werden kann, die vom neueren regex
Modul unterstützt werden. Die Idee ist:
forget_this | or this | and this as well | (but keep this)
Bei unserem Apfelbeispiel wäre dies:
import regex as re
string = "An apple a day keeps the doctor away (I eat an apple everyday)."
rx = re.compile(r'''
\([^()]*\) (*SKIP)(*FAIL) # match anything in parentheses and "throw it away"
| # or
apple # match an apple
''', re.VERBOSE)
apples = rx.findall(string)
print(apples)
# only one
Dies entspricht "Apfel" nur, wenn es außerhalb der Klammern gefunden werden kann.
So funktioniert das:
- Während von links nach rechts schauen, die Regex - Engine alles links verbraucht,
(*SKIP)
fungiert als „immer wahr Behauptung“. Danach fällt es bei(*FAIL)
und Backtracks korrekt aus. - Nun kommt es zum Punkt
(*SKIP)
von rechts nach links (aka beim Backtracking), wo es verboten ist, weiter nach links zu gehen. Stattdessen wird der Engine befohlen, alles nach links wegzuwerfen und zu dem Punkt zu springen, an dem(*SKIP)
aufgerufen wurde.