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) .


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow