Python Language
Wyrażenia regularne (Regex)
Szukaj…
Wprowadzenie
Python udostępnia wyrażenia regularne za pośrednictwem modułu re
.
Wyrażenia regularne to kombinacje znaków interpretowane jako reguły dopasowywania podciągów. Na przykład wyrażenie 'amount\D+\d+'
będzie pasować do dowolnego ciągu złożonego ze słowa amount
plus liczba całkowita, oddzielona jedną lub większą liczbą cyfr, takich jak: amount=100
, amount is 3
, amount is equal to: 33
itd.
Składnia
Bezpośrednie wyrażenia regularne
re.match (pattern, string, flag = 0) # Out: dopasuj wzór na początku łańcucha lub None
re.search (wzorzec, ciąg, flaga = 0) # Out: dopasowanie wzorca w ciągu lub Brak
re.findall (wzorzec, ciąg, flaga = 0) # Out: lista wszystkich dopasowań wzorca w ciągu lub []
re.finditer (wzór, ciąg, flaga = 0) # Wyjście: to samo co re.findall, ale zwraca obiekt iteratora
re.sub (wzorzec, zamiennik, ciąg, flaga = 0) # Out: ciąg z zastąpieniem (ciąg lub funkcja) zamiast wzorca
Wstępnie skompilowane wyrażenia regularne
precompiled_pattern = re.compile (wzorzec, flaga = 0)
precompiled_pattern.match (string) # Out: dopasowanie na początku łańcucha lub None
precompiled_pattern.search (string) # Out: dopasuj gdziekolwiek w ciągu lub None
precompiled_pattern.findall (string) # Out: lista wszystkich pasujących podciągów
precompiled_pattern.sub (string / pattern / function, string) # Out: zastąpiony ciąg
Dopasowanie początku łańcucha
Pierwszy argument re.match()
jest wyrażeniem regularnym, drugi to pasujący ciąg:
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'
Możesz zauważyć, że zmienna wzorca jest łańcuchem z prefiksem r
, co oznacza, że ciąg jest literałem surowego łańcucha .
Surowy literał ciągu ma nieco inną składnię niż literał łańcucha, mianowicie odwrotny ukośnik \
w nieprzetworzonym literale łańcucha oznacza „tylko odwrotny ukośnik” i nie ma potrzeby podwajania odwrotnych ukośników, aby uciec przed „sekwencjami ucieczki”, takimi jak znaki nowej linii ( \n
) , tabs ( \t
), backspace ( \
), form-feeds ( \r
) i tak dalej. W normalnych literałach łańcuchowych każdy odwrotny ukośnik musi zostać podwojony, aby uniknąć wzięcia go za początek sekwencji ucieczki.
Dlatego r"\n"
jest ciągiem 2 znaków: \
i n
. Wzory wyrażeń regularnych używają również odwrotnych ukośników, np. \d
odnosi się do dowolnego znaku cyfry. Możemy uniknąć konieczności podwójnego opuszczania naszych ciągów ( "\\d"
), używając nieprzetworzonych ciągów ( r"\d"
).
Na przykład:
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'
Dopasowywanie odbywa się tylko od początku ciągu. Jeśli chcesz dopasować gdziekolwiek, użyj zamiast tego re.search
.
match = re.match(r"(123)", "a123zzb")
match is None
# Out: True
match = re.search(r"(123)", "a123zzb")
match.group()
# Out: '123'
Badawczy
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.'
Wyszukiwanie odbywa się w dowolnym miejscu ciągu, w przeciwieństwie do re.match
. Możesz także użyć re.findall
.
Możesz także wyszukiwać na początku łańcucha (użyj ^
),
match = re.search(r"^123", "123zzb")
match.group(0)
# Out: '123'
match = re.search(r"^123", "a123zzb")
match is None
# Out: True
na końcu ciągu (użyj $
),
match = re.search(r"123$", "zzb123")
match.group(0)
# Out: '123'
match = re.search(r"123$", "123zzb")
match is None
# Out: True
lub oba (użyj obu ^
i $
):
match = re.search(r"^123$", "123")
match.group(0)
# Out: '123'
Grupowanie
Grupowanie odbywa się za pomocą nawiasów. Wywołanie group()
zwraca ciąg utworzony z pasujących podrzędnych podgrup.
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'
Do group()
można także podać argumenty, aby pobrać konkretną podgrupę.
Z dokumentów :
Jeśli występuje jeden argument, wynikiem jest pojedynczy ciąg; jeśli jest wiele argumentów, wynikiem jest krotka z jednym elementem na argument.
Z kolei wywoływanie groups()
zwraca listę krotek zawierających podgrupy.
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')
Nazwane grupy
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'
Tworzy grupę przechwytywania, do której można odwoływać się według nazwy oraz indeksu.
Grupy nie przechwytujące
Użycie (?:)
tworzy grupę, ale grupa nie jest przechwytywana. Oznacza to, że możesz używać go jako grupy, ale nie spowoduje to zanieczyszczenia „przestrzeni grupy”.
re.match(r'(\d+)(\+(\d+))?', '11+22').groups()
# Out: ('11', '+22', '22')
re.match(r'(\d+)(?:\+(\d+))?', '11+22').groups()
# Out: ('11', '22')
Ten przykład pasuje do 11+22
lub 11
, ale nie do 11+
. Dzieje się tak, ponieważ znak +
i drugi termin są zgrupowane. Z drugiej strony znak +
nie jest przechwytywany.
Ucieczka ze znaków specjalnych
Znaki specjalne (takie jak nawiasy klas znaków [
i ]
poniżej) nie są dosłownie dopasowane:
match = re.search(r'[b]', 'a[b]c')
match.group()
# Out: 'b'
Unikając znaków specjalnych, można je dosłownie dopasować:
match = re.search(r'\[b\]', 'a[b]c')
match.group()
# Out: '[b]'
Aby to re.escape()
możesz użyć funkcji re.escape()
:
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'
Funkcja re.escape()
unika wszystkich znaków specjalnych, więc jest przydatna, jeśli tworzysz wyrażenie regularne na podstawie danych wprowadzonych przez użytkownika:
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.!']
Zastąpienie
re.sub
można wykonać na ciągach znaków za pomocą re.sub
.
Zastępowanie ciągów
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'
Korzystanie z odniesień do grup
Zastąpienia małą liczbą grup można wykonać w następujący sposób:
re.sub(r"t([0-9])([0-9])", r"t\2\1", "t13 t19 t81 t25")
# Out: 't31 t91 t18 t52'
Jeśli jednak utworzysz identyfikator grupy, taki jak „10”, to nie zadziała : \10
zostanie odczytany jako „Numer identyfikacyjny 1, po którym następuje 0”. Musisz więc być bardziej szczegółowy i użyć notacji \g<i>
:
re.sub(r"t([0-9])([0-9])", r"t\g<2>\g<1>", "t13 t19 t81 t25")
# Out: 't31 t91 t18 t52'
Korzystanie z funkcji zastępczej
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'
Znajdź wszystkie nie pokrywające się mecze
re.findall(r"[0-9]{2,3}", "some 1 text 12 is 945 here 4445588899")
# Out: ['12', '945', '444', '558', '889']
Zauważ, że r
przed "[0-9]{2,3}"
mówi Pythonowi, aby interpretował ciąg takim, jaki jest; jako ciąg „surowy”.
Można również użyć re.finditer()
który działa w taki sam sposób jak re.findall()
ale zwraca iterator z obiektami SRE_Match
zamiast listy ciągów:
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
'''
Wstępnie skompilowane wzory
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
Kompilowanie wzorca pozwala na jego ponowne użycie w programie. Zauważ jednak, że Python buforuje ostatnio używane wyrażenia ( dokumenty , odpowiedź SO ), więc „programy używające tylko kilku wyrażeń regularnych jednocześnie nie muszą się martwić o kompilację wyrażeń regularnych” .
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
Może być używany z re.match ().
Sprawdzanie dozwolonych znaków
Jeśli chcesz sprawdzić, czy łańcuch zawiera tylko pewien zestaw znaków, w tym przypadku az, AZ i 0-9, możesz to zrobić w ten sposób,
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'
Możesz także dostosować linię wyrażeń z [^a-zA-Z0-9.]
Do [^a-z0-9.]
, Aby na przykład wyłączyć wielkie litery.
Częściowe uznanie: http://stackoverflow.com/a/1325265/2697955
Dzielenie łańcucha przy użyciu wyrażeń regularnych
Możesz także użyć wyrażeń regularnych do podzielenia łańcucha. Na przykład,
import re
data = re.split(r'\s+', 'James 94 Samantha 417 Scarlett 74')
print( data )
# Output: ['James', '94', 'Samantha', '417', 'Scarlett', '74']
Flagi
W niektórych szczególnych przypadkach musimy zmienić zachowanie wyrażenia regularnego, odbywa się to za pomocą flag. Flagi można ustawić na dwa sposoby, za pomocą słowa kluczowego flags
lub bezpośrednio w wyrażeniu.
Słowo kluczowe flagi
Poniżej przykład dla re.search
ale działa dla większości funkcji w module 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'
Wspólne flagi
Flaga | krótki opis |
---|---|
re.IGNORECASE , re.I | Sprawia, że wzór ignoruje obudowę |
re.DOTALL , re.S | Czyni . dopasuj wszystko, w tym nowe linie |
re.MULTILINE , re.M | Dopasowuje ^ do początku linii i $ do końca linii |
re.DEBUG | Włącza informacje debugowania |
Aby uzyskać pełną listę wszystkich dostępnych flag, sprawdź dokumenty
Flagi Inline
Z dokumentów :
(?iLmsux)
(Jedna lub więcej liter ze zbioru „i”, „L”, „m”, „s”, „u”, „x”.)Grupa dopasowuje pusty ciąg; litery ustawiają odpowiednie flagi: re.I (ignoruj wielkość liter), re.L (zależne od ustawień regionalnych), re.M (wieloliniowe), re.S (kropka pasuje do wszystkich), re.U (zależne od Unicode) i re.X (pełne), dla całego wyrażenia regularnego. Jest to przydatne, jeśli chcesz uwzględnić flagi jako część wyrażenia regularnego, zamiast przekazywać argument flagi do funkcji re.compile ().
Zauważ, że flaga (? X) zmienia sposób parsowania wyrażenia. Powinien być użyty najpierw w ciągu wyrażenia lub po jednym lub większej liczbie białych znaków. Jeśli przed flagą znajdują się znaki spacje, wyniki są niezdefiniowane.
Iteracja po meczach za pomocą `re.finditer`
Możesz użyć re.finditer
do iteracji wszystkich dopasowań w ciągu. To daje (w porównaniu do re.findall
dodatkowych informacji, takich jak informacje o lokalizacji dopasowania w ciągu (indeksy):
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))
Wynik:
Match "an" found at: [5,7]
Match "an" found at: [20,22]
Match "ant" found at: [23,26]
Dopasuj wyrażenie tylko w określonych lokalizacjach
Często chcesz dopasować wyrażenie tylko w określonych miejscach (to znaczy pozostawić je nietknięte w innych). Rozważ następujące zdanie:
An apple a day keeps the doctor away (I eat an apple everyday).
„Jabłko” występuje tutaj dwukrotnie, co można rozwiązać za pomocą tzw. Czasowników kontrolnych cofania, które są obsługiwane przez nowszy moduł regex
. Chodzi o to:
forget_this | or this | and this as well | (but keep this)
W naszym przykładzie jabłka byłoby to:
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
To pasuje do „jabłka” tylko wtedy, gdy można je znaleźć poza nawiasami.
Oto jak to działa:
- Patrząc od lewej do prawej , silnik regex zużywa wszystko w lewo,
(*SKIP)
działa jak „zawsze prawdziwe twierdzenie”. Następnie poprawnie zawiesza się(*FAIL)
i wycofuje się. - Teraz dochodzi do punktu
(*SKIP)
od prawej do lewej (aka podczas cofania), gdzie nie wolno iść dalej w lewo. Zamiast tego polecono silnikowi wyrzucić cokolwiek w lewo i przeskoczyć do miejsca, w którym(*SKIP)
.