Zanurkuj w Pythonie/Rozwlekłe wyrażenia regularne
(Przekierowano z Python/Rozwlekłe wyrażenia regularne)
Rozwlekłe wyrażenia regularne
edytujJak na razie, mieliśmy do czynienia z czymś, co nazywam "zwięzłymi" wyrażeniami regularnymi. Jak pewnie zauważyliśmy, są one trudne do odczytania i nawet, jeśli już je rozszyfrujemy, nie ma gwarancji, że zrobimy to za np. sześć miesięcy. To, czego potrzebujemy, to dokumentacja w ich treści.
Python pozwala na to przez tworzenie rozwlekłych wyrażeń regularnych (ang. verbose regular expressions). Różnią się one od zwięzłych dwoma rzeczami:
- Białe znaki są ignorowane. Spacje, znaki tabulacji, znaki nowej linii nie są dopasowywane jako spacje, znaki tabulacji lub znaki nowej linii. Znaki te nie są w ogóle dopasowywane. (Jeśli byśmy chcieli jednak dopasować któryś z nich, musisz poprzedzić je odwrotnym ukośnikiem (\).)
- Komentarze są ignorowane. Komentarz w rozwlekłym wyrażeniu regularnym wygląda dokładnie tak samo, jak w kodzie Pythona: zaczyna się od # i leci aż do końca linii. W tym przypadku jest to komentarz w wieloliniowym łańcuchu znaków, a nie w kodzie źródłowym, ale zasada działania jest taka sama.
Łatwiej będzie to zrozumieć jeśli skorzystamy z przykładu. Skorzystajmy ze zwięzłego wyrażenia regularnego, które utworzyliśmy wcześniej i zróbmy z niego rozwlekłe. Ten przykład pokazuje jak.
Przykład. Wyrażenia regularne z komentarzami
>>> pattern = """ ^ # początek łańcucha znaków M{0,3} # tysiące - 0 do 3 M (CM|CD|D?C{0,3}) # setki - 900 (CM), 400 (CD), 0-300 (0 do 3 C), # lub 500-800 (D, a po nim 0 do 3 C) (XC|XL|L?X{0,3}) # dziesiątki - 90 (XC), 40 (XL), 0-30 (0 do 3 X), # lub 50-80 (L, a po nim 0 do 3 X) (IX|IV|V?I{0,3}) # jedności - 9 (IX), 4 (IV), 0-3 (0 do 3 I), # lub 5-8 (V, a po nim 0 do 3 I) $ # koniec łańcucha znaków """ >>> re.search(pattern, 'M', re.VERBOSE) #(1) <_sre.SRE_Match object at 0x008EEB48> >>> re.search(pattern, 'MCMLXXXIX', re.VERBOSE) #(2) <_sre.SRE_Match object at 0x008EEB48> >>> re.search(pattern, 'MMMDCCCLXXXVIII', re.VERBOSE) #(3) <_sre.SRE_Match object at 0x008EEB48> >>> re.search(pattern, 'M') #(4)
- Najważniejszą rzeczą o której należy pamiętać, gdy korzystamy z rozwlekłych wyrażeń regularnych jest to, że musimy przekazać dodatkowy argument:
re.VERBOSE
. Jest to stała zdefiniowana w modulere
, która sygnalizuje, że wyrażenie powinno być traktowane jako rozwlekłe. Jak widzimy, ten wzorzec ma mnóstwo białych znaków (które są ignorowane) i kilka komentarzy (które też są ignorowane). Gdy usuniemy białe znaki i komentarze, to pozostanie dokładnie to samo wyrażenie regularne, jakie otrzymaliśmy w poprzednim przykładzie, ale o wiele mniej czytelne. (Zauważmy, że co prawda łańcuch znaków posiada polskie znaki, ale nie tworzymy go w unikodzie, ponieważ i tak te znaki nie mają dla nas żadnego znaczenia, ponieważ są w komentarzach.) - To dopasowuje początek łańcucha, potem jedno z trzech możliwych M, potem CM, L i trzy z trzech możliwych X, a następnie IX i koniec łańcucha.
- To dopasowuje początek łańcucha, potem trzy z trzech możliwych M, dalej D, trzy z trzech możliwych C, L z trzema możliwymi X, potem V z trzema możliwymi I i na koniec koniec łańcucha.
- Tutaj nie udało się dopasować niczego. Czemu? Ponieważ nie przekazaliśmy flagi
re.VERBOSE
, więc funkcjare.search
traktuje to wyrażenie regularne jako zwięzłe, z dużą ilością białych znaków i kratek. Python nie rozpoznaje samodzielnie, czy każemy mu dopasować zwięzłe, czy może rozwlekłe wyrażenie regularne i przyjmuje, że każde jest zwięzłe, chyba że wyraźnie wskażemy, że tak nie jest.