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.


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow