Jak używać modułu wyrażeń regularnych Pythona re (match, search, sub, itd.)

Biznes

Aby wykonać przetwarzanie wyrażeń regularnych w Pythonie, używamy modułu re z biblioteki standardowej. Pozwala on na wyodrębnianie, zastępowanie i dzielenie łańcuchów przy użyciu wzorców wyrażeń regularnych.

W tym rozdziale, najpierw wyjaśnimy funkcje i metody modułu re.

  • Kompilowanie wzorców wyrażeń regularnych:compile()
  • obiekt meczowy
  • Sprawdź, czy początek łańcucha pasuje, wyodrębnij:match()
  • Sprawdź, czy mecze nie ograniczają się do początku:search()
  • Sprawdza, czy cały łańcuch pasuje:fullmatch()
  • Pobierz listę wszystkich pasujących części:findall()
  • Pobierz wszystkie pasujące części jako iterator:finditer()
  • Wymienić pasującą część:sub(),subn()
  • Dzielenie łańcuchów za pomocą wzorców wyrażeń regularnych:split()

Po tym, wyjaśnię metaznaki (znaki specjalne) i specjalne sekwencje wyrażeń regularnych, które mogą być użyte w module re. Zasadniczo, jest to standardowa składnia wyrażeń regularnych, ale należy uważać na ustawianie flag (szczególnie re.ASCII).

  • Metaznaki wyrażeń regularnych, sekwencje specjalne i zastrzeżenia w Pythonie
  • Ustawianie flagi
    • Ograniczenie do znaków ASCII:re.ASCII
    • Nie rozróżnia się wielkości liter:re.IGNORECASE
    • Dopasuj początek i koniec każdego wiersza:re.MULTILINE
    • Określenie wielu flag
  • Mecze zachłanne i nie zachłanne

Skompiluj wzór wyrażenia regularnego: compile()

Przetwarzanie wyrażeń regularnych w module re można wykonać na dwa sposoby.

Działaj z funkcją

Pierwszym z nich jest funkcja.re.match(),re.sub()Funkcje takie jak te są dostępne do wykonywania ekstrakcji, zamiany i innych procesów przy użyciu wzorców wyrażeń regularnych.

Szczegóły funkcji zostaną opisane później, ale we wszystkich z nich pierwszym argumentem jest łańcuch wzorca wyrażenia regularnego, a następnie łańcuch do przetworzenia i tak dalej. Na przykład, w funkcji re.sub(), która wykonuje podstawianie, drugim argumentem jest łańcuch podstawiania, a trzecim – łańcuch do przetworzenia.

import re

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.match(r'([a-z]+)@([a-z]+)\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

result = re.sub(r'([a-z]+)@([a-z]+)\.com', 'new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

Zauważ, że [a-z] we wzorcu wyrażenia regularnego w tym przykładzie oznacza dowolny znak od a do z (tj. małe litery alfabetu), a + oznacza powtórzenie poprzedniego wzorca (w tym przypadku [a-z]) jeden lub więcej razy. Wzorzec [a-z]+ pasuje do każdego łańcucha, który powtarza jeden lub więcej znaków alfabetu małych liter.

. jest metaznakiem (znakiem o specjalnym znaczeniu) i musi być usunięty za pomocą odwrotnego ukośnika.

Ponieważ łańcuchy wzorców wyrażeń regularnych często używają wielu backslashes, wygodnie jest używać surowych łańcuchów, jak w przykładzie.

Uruchamia metodę w obiekcie wzorca wyrażenia regularnego

Drugim sposobem przetwarzania wyrażeń regularnych w module re jest metoda obiektu wzorca wyrażeń regularnych.

Używając re.compile(), możesz skompilować łańcuch wzorca wyrażeń regularnych, aby utworzyć obiekt wzorca wyrażeń regularnych.

p = re.compile(r'([a-z]+)@([a-z]+)\.com')

print(p)
# re.compile('([a-z]+)@([a-z]+)\\.com')

print(type(p))
# <class 're.Pattern'>

re.match(),re.sub()Na przykład, ten sam proces co te funkcje może być wykonany jako metody match(),sub() obiektów wyrażeń regularnych.

m = p.match(s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

result = p.sub('new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

Wszystkie opisane poniżej funkcje re.xxx() są również udostępniane jako metody obiektu wyrażenia regularnego.

Jeśli powtarzasz proces, który używa tego samego wzorca, bardziej efektywne jest wygenerowanie obiektu wyrażenia regularnego za pomocą re.compile() i używanie go dookoła.

W poniższym przykładowym kodzie, dla wygody, funkcja jest używana bez kompilacji, ale jeśli chcesz używać tego samego wzorca wielokrotnie, zalecane jest wcześniejsze skompilowanie go i wykonanie jako metody obiektu wyrażenia regularnego.

obiekt meczowy

match(), search(), itd. zwracają obiekt dopasowania.

s = 'aaa@xxx.com'

m = re.match(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(type(m))
# <class 're.Match'>

Dopasowany łańcuch i pozycja są uzyskiwane przy pomocy następujących metod obiektu match.

  • Uzyskaj lokalizację meczu:start(),end(),span()
  • Uzyskaj dopasowany łańcuch:group()
  • Uzyskaj ciąg znaków dla każdej grupy:groups()
print(m.start())
# 0

print(m.end())
# 11

print(m.span())
# (0, 11)

print(m.group())
# aaa@xxx.com

Jeśli zawrzesz część wzorca wyrażenia regularnego w łańcuchu z nawiasami(), część ta zostanie przetworzona jako grupa. W tym przypadku, łańcuch części, która pasuje do każdej grupy w groups() może być otrzymany jako tuple.

m = re.match(r'([a-z]+)@([a-z]+)\.([a-z]+)', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(m.groups())
# ('aaa', 'xxx', 'com')

Sprawdź, czy początek łańcucha pasuje, wyciągnij: match()

match() zwraca obiekt dopasowania, jeśli początek łańcucha pasuje do wzorca.

Jak wspomniano powyżej, obiekt dopasowania może być użyty do wyodrębnienia dopasowanego podłańcucha, lub po prostu do sprawdzenia, czy nastąpiło dopasowanie.

match() sprawdzi tylko początek. Jeśli nie ma pasującego łańcucha na początku, zwraca Brak.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.match(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

m = re.match(r'[a-z]+@[a-z]+\.net', s)
print(m)
# None

Sprawdza dopasowania nie ograniczone do początku, wyciąg: search()

Podobnie jak match(), zwraca obiekt match jeśli pasuje.

Jeśli istnieje wiele pasujących części, zwrócona zostanie tylko pierwsza pasująca część.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.search(r'[a-z]+@[a-z]+\.net', s)
print(m)
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

m = re.search(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

Jeśli chcesz uzyskać wszystkie pasujące części, użyj findall() lub finditer() jak opisano poniżej.

Sprawdź, czy cały łańcuch pasuje: fullmatch()

Aby sprawdzić czy cały łańcuch pasuje do wzorca wyrażenia regularnego, użyj fullmatch(). Jest to przydatne, na przykład, do sprawdzenia czy ciąg znaków jest poprawny jako adres email czy nie.

Jeśli cały łańcuch pasuje, zwracany jest obiekt dopasowania.

s = 'aaa@xxx.com'

m = re.fullmatch(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

Jeśli istnieją niedopasowane części (tylko częściowe dopasowania lub brak dopasowań), zwracane jest Brak.

s = '!!!aaa@xxx.com!!!'

m = re.fullmatch(r'[a-z]+@[a-z]+\.com', s)
print(m)
# None

Funkcja fullmatch() została dodana w Pythonie 3.4. Jeśli chcesz zrobić to samo we wcześniejszych wersjach, użyj match() i pasującego metaznaku $ na końcu. Jeśli cały łańcuch od początku do końca nie pasuje, zwraca ona Brak.

s = '!!!aaa@xxx.com!!!'

m = re.match(r'[a-z]+@[a-z]+\.com$', s)
print(m)
# None

Uzyskaj listę wszystkich pasujących części: findall()

findall() zwraca listę wszystkich pasujących podłańcuchów. Zauważ, że elementy listy nie są obiektami dopasowania, lecz łańcuchami.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.findall(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(result)
# ['aaa@xxx.com', 'bbb@yyy.com', 'ccc@zzz.net']

Liczbę dopasowanych elementów można sprawdzić za pomocą wbudowanej funkcji len(), która zwraca liczbę elementów na liście.

print(len(result))
# 3

Grupowanie za pomocą nawiasów() we wzorcu wyrażenia regularnego zwraca listę krotek, których elementami są łańcuchy każdej z grup. Jest to odpowiednik funkcji groups() w obiekcie match.

result = re.findall(r'([a-z]+)@([a-z]+)\.([a-z]+)', s)
print(result)
# [('aaa', 'xxx', 'com'), ('bbb', 'yyy', 'com'), ('ccc', 'zzz', 'net')]

Grupa nawiasów () może być zagnieżdżona, więc jeśli chcesz uzyskać cały mecz, po prostu zawrzyj cały mecz w nawiasach ().

result = re.findall(r'(([a-z]+)@([a-z]+)\.([a-z]+))', s)
print(result)
# [('aaa@xxx.com', 'aaa', 'xxx', 'com'), ('bbb@yyy.com', 'bbb', 'yyy', 'com'), ('ccc@zzz.net', 'ccc', 'zzz', 'net')]

Jeśli nie zostanie znalezione żadne dopasowanie, zwracana jest pusta krotka.

result = re.findall('[0-9]+', s)
print(result)
# []

Pobierz wszystkie pasujące części jako iterator: finditer()

finditer() zwraca wszystkie pasujące elementy jako iterator. Elementy nie są łańcuchami jak w findall(), ale obiektami dopasowania, więc możesz uzyskać pozycję (indeks) dopasowanych części.

Sam iterator nie może być wypisany za pomocą print() aby uzyskać jego zawartość. Jeśli użyjesz wbudowanej funkcji next() lub instrukcji for, możesz uzyskać zawartość jeden po drugim.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(result)
# <callable_iterator object at 0x10b0efa90>

print(type(result))
# <class 'callable_iterator'>

for m in result:
    print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
# <re.Match object; span=(13, 24), match='bbb@yyy.com'>
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

Może być również przekonwertowana na listę za pomocą list().

l = list(re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s))
print(l)
# [<re.Match object; span=(0, 11), match='aaa@xxx.com'>, <re.Match object; span=(13, 24), match='bbb@yyy.com'>, <re.Match object; span=(26, 37), match='ccc@zzz.net'>]

print(l[0])
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(type(l[0]))
# <class 're.Match'>

print(l[0].span())
# (0, 11)

Jeśli chcesz uzyskać pozycję wszystkich pasujących części, notacja list comprehension jest wygodniejsza niż list().

print([m.span() for m in re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)])
# [(0, 11), (13, 24), (26, 37)]

Iterator wyciąga elementy w kolejności. Zauważ, że jeśli spróbujesz wydobyć więcej elementów po osiągnięciu końca, zostaniesz z niczym.

result = re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)

for m in result:
    print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
# <re.Match object; span=(13, 24), match='bbb@yyy.com'>
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

print(list(result))
# []

Zamień pasujące części: sub(), subn()

Używając sub(), możesz zastąpić dopasowaną część innym łańcuchem. Podstawiony łańcuch zostanie zwrócony.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.sub(r'[a-z]+@[a-z]+\.com', 'new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

print(type(result))
# <class 'str'>

Podczas grupowania za pomocą nawiasów(), dopasowany łańcuch może być użyty w zastępowanym łańcuchu.

Domyślnie, obsługiwane są następujące elementy: Zauważ, że dla normalnych łańcuchów, które nie są surowymi łańcuchami, przed backslashem musi być wymieniony odwrotny ukośnik, aby uciec od backslasha.

\1Pierwszy nawias
\2Drugi nawias
\3Trzeci nawias
result = re.sub(r'([a-z]+)@([a-z]+)\.com', r'\1@\2.net', s)
print(result)
# aaa@xxx.net, bbb@yyy.net, ccc@zzz.net

?P<xxx>
Jeśli nadasz grupie nazwę, wpisując ją na początku nawiasów wzorca wyrażenia regularnego, możesz określić ją używając nazwy zamiast liczby, jak pokazano poniżej.
\g<xxx>

result = re.sub(r'(?P<local>[a-z]+)@(?P<SLD>[a-z]+)\.com', r'\g<local>@\g<SLD>.net', s)
print(result)
# aaa@xxx.net, bbb@yyy.net, ccc@zzz.net

Argument count określa maksymalną liczbę zamian. Zastąpiony zostanie tylko licznik z lewej strony.

result = re.sub(r'[a-z]+@[a-z]+\.com', 'new-address', s, count=1)
print(result)
# new-address, bbb@yyy.com, ccc@zzz.net

subn() zwraca tuple podstawionego łańcucha (taką samą jak wartość zwracana przez sub()) oraz liczbę podstawionych części (liczbę, która pasuje do wzorca).

result = re.subn(r'[a-z]+@[a-z]+\.com', 'new-address', s)
print(result)
# ('new-address, new-address, ccc@zzz.net', 2)

Metoda określania argumentów jest taka sama jak sub(). Możesz użyć części zgrupowanej w nawiasach, lub podać liczbę argumentów.

result = re.subn(r'(?P<local>[a-z]+)@(?P<SLD>[a-z]+)\.com', r'\g<local>@\g<SLD>.net', s)
print(result)
# ('aaa@xxx.net, bbb@yyy.net, ccc@zzz.net', 2)

result = re.subn(r'[a-z]+@[a-z]+\.com', 'new-address', s, count=1)
print(result)
# ('new-address, bbb@yyy.com, ccc@zzz.net', 1)

Dzielenie ciągów za pomocą wzorców wyrażeń regularnych: split()

split() dzieli łańcuch na część pasującą do wzorca i zwraca go jako listę.

Zauważ, że pierwsze i ostatnie dopasowanie będzie zawierać puste łańcuchy na początku i końcu listy wynikowej.

s = '111aaa222bbb333'

result = re.split('[a-z]+', s)
print(result)
# ['111', '222', '333']

result = re.split('[0-9]+', s)
print(result)
# ['', 'aaa', 'bbb', '']

Argument maxsplit określa maksymalną liczbę podziałów (kawałków). Tylko liczba z lewej strony zostanie podzielona.

result = re.split('[a-z]+', s, 1)
print(result)
# ['111', '222bbb333']

Metaznaki wyrażeń regularnych, sekwencje specjalne i zastrzeżenia w Pythonie

Główne metaznaki wyrażeń regularnych (znaki specjalne) i sekwencje specjalne, które mogą być używane w module Python 3 re są następujące

metaznakspis treści
.Dowolny pojedynczy znak inny niż nowa linia (w tym nowa linia z flagą DOTALL)
^Początek łańcucha (pasuje również do początku każdej linii z flagą MULTILINE)
$Koniec łańcucha (pasuje również do końca każdej linii z flagą MULTILINE)
*Powtórzenie poprzedniego wzoru więcej niż 0 razy
+Powtórz poprzedni wzór co najmniej raz.
?Powtórzenie poprzedniego wzoru 0 lub 1 raz
{m}Powtórzenie poprzedniego wzoru m razy
{m, n}Ostatni wzór.m~npowtórz
[]Zestaw znaków[]Pasuje do dowolnego z tych znaków
|LUBA|BPasuje do wzorca A lub B
sekwencja specjalnaspis treści
\dLiczby dziesiętne Unicode (ograniczone do liczb ASCII przez flagę ASCII)
\D\dZnaczenie przeciwne do tego.
\sBiałe znaki spacji Unicode (ograniczone do białych znaków spacji ASCII za pomocą flagi ASCII)
\S\sZnaczenie przeciwne do tego.
\wZnaki słowne i podkreślniki Unicode (ograniczone do znaków alfanumerycznych i podkreślników ASCII za pomocą flagi ASCII)
\W\wZnaczenie przeciwne do tego.

Nie wszystkie z nich są wymienione w tej tabeli. Pełną listę można znaleźć w oficjalnej dokumentacji.

Zauważ również, że niektóre znaczenia są inne w Pythonie 2.

Ustawianie flagi

Jak pokazano w powyższej tabeli, niektóre metaznaki i sekwencje specjalne zmieniają swój tryb w zależności od flagi.

Tylko główne flagi są tutaj opisane. Zobacz oficjalną dokumentację dla reszty.

Ograniczenie do znaków ASCII: re.ASCII

\wBędzie to również pasowało do dwubajtowych kanji, znaków alfanumerycznych, itp. domyślnie dla łańcuchów Pythona 3. Nie jest to równoważne poniższemu, ponieważ nie jest to standardowe wyrażenie regularne.[a-zA-Z0-9_]

m = re.match(r'\w+', '漢字ABC123')
print(m)
# <re.Match object; span=(0, 11), match='漢字ABC123'>

m = re.match('[a-zA-Z0-9_]+', '漢字ABC123')
print(m)
# None

Jeśli podasz re.ASCII jako argument flag w każdej funkcji lub dodasz poniższą flagę inline na początku łańcucha wzorca wyrażenia regularnego, będzie ono dopasowywać tylko znaki ASCII (nie będzie dopasowywać dwubajtowych znaków japońskich, znaków alfanumerycznych itd.)
(?a)
W tym przypadku dwa poniższe są równoważne.
\w=[a-zA-Z0-9_]

m = re.match(r'\w+', '漢字ABC123', flags=re.ASCII)
print(m)
# None

m = re.match(r'(?a)\w+', '漢字ABC123')
print(m)
# None

To samo dotyczy kompilacji przy użyciu re.compile(). Użyj flag argumentu lub flag inline.

p = re.compile(r'\w+', flags=re.ASCII)
print(p)
# re.compile('\\w+', re.ASCII)

print(p.match('漢字ABC123'))
# None

p = re.compile(r'(?a)\w+')
print(p)
# re.compile('(?a)\\w+', re.ASCII)

print(p.match('漢字ABC123'))
# None

ASCII jest również dostępne jako krótka forma re. A. Możesz użyć albo.

print(re.ASCII is re.A)
# True

Na \W, przeciwieństwo \W, mają również wpływ re.ASCII i flagi inline.

m = re.match(r'\W+', '漢字ABC123')
print(m)
# None

m = re.match(r'\W+', '漢字ABC123', flags=re.ASCII)
print(m)
# <re.Match object; span=(0, 11), match='漢字ABC123'>

Podobnie jak w przypadku \w, dwa poniższe domyślnie dopasowują zarówno znaki jedno- jak i dwubajtowe, ale są ograniczone do jednobajtowych, jeśli podano flagi re.ASCII lub inline.

  • Dopasuj liczby\d
  • Dopasowuje puste miejsce\s
  • Dopasowuje liczby nie będące liczbami\D
  • Dopasowuje dowolny element niebędący spacją.\S
m = re.match(r'\d+', '123')
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123')
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123', flags=re.ASCII)
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123', flags=re.ASCII)
print(m)
# None

m = re.match(r'\s+', ' ')  # full-width space
print(m)
# <re.Match object; span=(0, 1), match='\u3000'>

m = re.match(r'\s+', ' ', flags=re.ASCII)
print(m)
# None

Nie rozróżnia się wielkości liter:re.IGNORECASE

Domyślnie, rozróżniana jest wielkość liter. Aby dopasować obie te wielkości, musisz zawrzeć we wzorcu zarówno duże jak i małe litery.

re.IGNORECASEJeśli zostanie podana, będzie pasować bez względu na wielkość liter. Równoważne z flagą i w standardowych wyrażeniach regularnych.

m = re.match('[a-zA-Z]+', 'abcABC')
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

m = re.match('[a-z]+', 'abcABC', flags=re.IGNORECASE)
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

m = re.match('[A-Z]+', 'abcABC', flags=re.IGNORECASE)
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

Możesz użyć mniej niż lub równy.

  • flaga inline(?i)
  • skrótre.I

Dopasuj początek i koniec każdego wiersza:re.MULTILINE

^Znaki meta w tym wyrażeniu regularnym pasują do początku łańcucha.

Domyślnie, dopasowywany jest tylko początek całego łańcucha, ale poniższe dopasuje również początek każdej linii. Równoważne z flagą m w standardowych wyrażeniach regularnych.
re.MULTILINE

s = '''aaa-xxx
bbb-yyy
ccc-zzz'''

print(s)
# aaa-xxx
# bbb-yyy
# ccc-zzz

result = re.findall('[a-z]+', s)
print(result)
# ['aaa', 'xxx', 'bbb', 'yyy', 'ccc', 'zzz']

result = re.findall('^[a-z]+', s)
print(result)
# ['aaa']

result = re.findall('^[a-z]+', s, flags=re.MULTILINE)
print(result)
# ['aaa', 'bbb', 'ccc']

$Dopasowuje koniec łańcucha. Domyślnie, dopasowywany jest tylko koniec całego łańcucha.
re.MULTILINEJeśli podasz tę wartość, będzie ona również pasować do końca każdej linii.

result = re.findall('[a-z]+$', s)
print(result)
# ['zzz']

result = re.findall('[a-z]+$', s, flags=re.MULTILINE)
print(result)
# ['xxx', 'yyy', 'zzz']

Możesz użyć mniej niż lub równy.

  • flaga inline(?m)
  • skrótre.M

Określenie wielu flag

|Jeśli chcesz włączyć wiele flag w tym samym czasie, użyj tego. W przypadku flag inline, po każdym znaku musi następować litera, jak pokazano poniżej.
(?am)

s = '''aaa-xxx
漢漢漢-字字字
bbb-zzz'''

print(s)
# aaa-xxx
# 漢漢漢-字字字
# bbb-zzz

result = re.findall(r'^\w+', s, flags=re.M)
print(result)
# ['aaa', '漢漢漢', 'bbb']

result = re.findall(r'^\w+', s, flags=re.M | re.A)
print(result)
# ['aaa', 'bbb']

result = re.findall(r'(?am)^\w+', s)
print(result)
# ['aaa', 'bbb']

Mecze zachłanne i nie zachłanne

Jest to ogólny problem z wyrażeniami regularnymi, a nie tylko problem z Pythonem, ale napiszę o nim, ponieważ ma tendencję do pakowania mnie w kłopoty.

Domyślnie, poniższe jest dopasowaniem zachłannym, które dopasowuje najdłuższy możliwy łańcuch.

  • *
  • +
  • ?
s = 'aaa@xxx.com, bbb@yyy.com'

m = re.match(r'.+com', s)
print(m)
# <re.Match object; span=(0, 24), match='aaa@xxx.com, bbb@yyy.com'>

print(m.group())
# aaa@xxx.com, bbb@yyy.com

Znak ? po nim spowoduje, że dopasowanie nie będzie miało charakteru zachłannego, minimalnego, dopasowując najkrótszy możliwy łańcuch.

  • *?
  • +?
  • ??
m = re.match(r'.+?com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(m.group())
# aaa@xxx.com

Zauważ, że domyślne dopasowywanie zachłanne może dopasowywać nieoczekiwane łańcuchy.