6. diel - Regulárne výrazy v Pythone
V minulej lekcii, Iterátory druhýkrát - Generátory v Pythone, sme si vytvorili vlastný iterátor, zoznámili sa s generátormi a preskúmali ich výhody.
V nasledujúcom tutoriále kolekcií v Pythone urobíme cimrmanovský krok bokom a zameriame sa na regulárne výrazy. Do kolekcií ich radíme preto, pretože ich využijeme najmä pri spracovávaní veľkého objemu dát a textov. A na to sú kolekcie stvorené. Regulárne výrazy nám umožňujú v Pythone vykonávať analýzu textu. Je to metóda, pomocou ktorej sa na základe vzoru rozpoznávajú alebo získavajú dáta.
Regulárne výrazy
Regulárne výrazy vznikli z dôvodu potreby práce s textovými reťazcami určitým unifikovaným spôsobom. Sú zaujímavým nástrojom nielen na overenie, či zadaný textový reťazec spĺňa určené pravidlá (validácia), ale tiež nám umožňujú vyhľadávať určitej podreťazce. Zbavíme sa tak mnohokrát aj niekoľkých vnorených podmienok.
Regulárne výrazy nám tiež pomôžu s filtrovaním dát z formulára, vyhľadávaním v texte alebo spracovávaním reťazcov. Najčastejšie ich využijeme pri overovaní položiek formulára. S regulárnymi výrazmi sa dá robiť plno vecí, napríklad zvýrazňovať slová v texte alebo treba meniť formát dátumu.
Regulárny výraz, čiže regex, je textový reťazec zložený z určitých znakov. Gramatika regulárnych výrazov nie je zložitá, ale je pomerne neprehľadná, a preto je dobré už napísané výrazy komentovať.
Na úvod si ukážeme príklad regulárneho výrazu:
[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}
Cieľom tohto regulárneho výrazu je zjednodušene zistiť, či je vložený textový reťazec emailom.
Výraz je dosť zjednodušený, takže niektoré neplatné adresy ním prejdú.
Zápis regulárnych výrazov
Teraz sa zoznámime s kvantifikátormi a zástupnými znakmi. Uvedieme si aj nejaké ďalšie konštrukcie.
Kvantifikátory
Kvantifikátory nám hovoria, koľkokrát sa budú znaky opakovať.
Kvantifikátorov je niekoľko typov, napríklad:
{X}
, kdeX
udáva počet opakovaní,{X, Y}
, kdeX `je minimální a `Y
maximálny počet opakovaní,- preddefinované kvantifikátory.
^.{4}$
Vypíšme si kvantifikátory do tabuľky:
Znak | Význam |
---|---|
. | jeden ľubovoľný znak |
* | žiadny alebo viac znakov |
+ | jeden alebo viac znakov |
? | žiadny alebo jeden znak |
{X} | X znakov |
{X , } | X a viac znakov |
{X,Y} | Medzi X a Y znaky |
Otáznik ?
je alternatívou k {0, 1}
. Hviezdička
*
k {0-∞}
a plus +
k
{1-∞}
. Pri preddefinovanej hviezdičke a pluske to funguje pre
maximálne nekonečno.
Ukážme si funkcionalitu kvantifikátora .
, ktorý nahrádza
ľubovoľný znak. Napríklad pre výraz ....
bude
platiť čokoľvek, čo má štyri znaky:
Cdf
= nie platné
Ahoj
= platné
A@x9
= platné
A@x9O
= platné
Ako je možné, že výraz A@x9O
obsahujúci päť
znakov je platný pre výraz ....
? Ukážme si
postup vyhodnotenia:
- Prvý znak je bodka - výraz zatiaľ splnený.
- Druhý znak je bodka - výraz zatiaľ splnený.
- Tretí znak je bodka - výraz zatiaľ splnený.
- Štvrtý znak je bodka - výraz zatiaľ splnený.
- Žiadny ďalší znak vo výraze, výraz bol splnený.
^
(AltGr + 9 +
4), ktorá zaistí, že na začiatku reťazca bude testovaný text.
Za výraz dáme dolár $
(AltGr +
ov).
Pokiaľ je naším cieľom zaistiť, že celý reťazec má byť presne
štyri znaky dlhý, mali by sme použiť výraz ^....$
.
Metaznak $
zaisťuje overenie od konca
reťazca. Teda od konca overíme, či reťazec spĺňa pravidlo odzadu
aj odpredu. V zátvorkách sa už pravidlo overuje bežným smerom. Znaky
^
a $
si preberieme nižšie v ďalších
konštrukciách.
Zástupné znaky
Zástupné znaky skracujú výraz a nahrádzajú nejaký znak alebo konštrukciu:
Znak | Význam |
---|---|
\t | tabulátor |
\n | nový riadok |
\b | začiatok alebo koniec slova |
\d | číslica |
\D | znak, ktorý nie je číslicou |
\w | písmená a číslice vrátane podčiarkovníka |
\W | znak, ktorý nie je písmeno, číslica vrátane podčiarkovníka |
\B | pozície, , Ktoré nie je na začiatku ani na konci slova |
\s | neviditeľný znak |
\S | znak, ktorý nie je neviditeľný znak |
\\ | spätná lomka |
\d
sú čísla 0-9
, teda výraz je totožný s
výrazom [0-9]
. Výraz \D
je totožný s výrazom
[^0-9]
.
Ďalšia konštrukcia
Nakoniec sa pozrieme na niektoré ďalšie konštrukcie:
Znak | Význam |
---|---|
abc | reťazec abc |
[abc] | jeden zo znakov a, b, c |
[^abc] | jeden znak okrem a, b, c (negácia) |
[az] | malé písmená |
[AZ] | veľké písmená |
[^A-Za-z0-9] | symbol (čokoľvek okrem písmena a čísla) |
^abc | abc na začiatku reťazca |
abc$ | abc na konci reťazca |
^abc$ | celý reťazec musí byť abc |
^
označuje začiatok reťazca. Dolár $
potom jeho koniec.
Hranaté zátvorky ukazujú na skupinu znakov, ktoré
reťazec smie alebo nesmie obsahovať. Ak ich smie obsahovať, tak ich
jednoducho napíšeme do zátvorky (ničím ich neoddeľujeme). Pokiaľ ich
naopak nesmie obsahovať, pridáme pred znakmi ešte striešku
^
(Alt + 9 + 4).
Ak chceme určiť, že sa má overovať napríklad abeceda,
tak uvedieme [a-zA-z]
. Týmto zaistíme, že sa skontrolujú
všetky znaky, ktoré sú medzi az
a AZ
. Znaky sa
berú z ASCII tabuľky, takže možno č
daný výraz nesplnia.
Escapovanie
Niekedy potrebujeme vo výraze použiť nejaký metaznak.
Treba chceme overiť, či užívateľ zadal ahoj|světe
.
Jednotlivé špeciálne znaky musíme odcapiť, teda predsadiť
spätným lomítkom (AltGr + Q). Výraz potom bude
vyzerať nasledovne:
\(ahoj\|svete\)
Použitie regexov v praxi
Poďme si teraz ukázať použitie regulárnych výrazov s modulom re zo štandardnej knižnice Pythonu.
Validácia
Validácia je jedným zo základných spôsobov použitia regexov. V podstate
sa pýtame, či reťazec zodpovedá zadanému predpisu. Využijeme na to funkciu
re.match()
. Funkcia je súčasťou modulu re v Pythone a slúži na
porovnanie zadaného reťazca so vzorcom regulárneho výrazu. Táto funkcia sa
pokúsi nájsť zhodu na začiatku zadaného reťazca a vráti objekt
Match
, ak je zhoda nájdená, alebo None
, pokiaľ
zhoda nájdená nie je.
Syntax funkcie re.match()
je nasledovná:
re.match(pattern, string, flags=0)
Parametre funkcie sú nasledujúce:
pattern
- regulárny výraz, s ktorým chceme porovnať zadaný reťazec,string
- reťazec, ktorý chceme porovnať s vzorcom,flags
- voliteľný parameter, ktorý určuje možnosti pre hľadanie zhôd (napríklad ignorovanie veľkosti písmen a podobne).
import re # definujeme vzorec pro e-mailovou adresu pattern = r'^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$' # zadáme e-mailovou adresu, kterou chceme ověřit email = '[email protected]' # ověříme, zda e-mailová adresa odpovídá vzorci if re.match(pattern, email): print('E-mailová adresa je platná.') else: print('E-mailová adresa není platná.')
Vo výstupe vidíme:
Výstup funkce match():
E-mailová adresa je platná.
V tomto príklade definujeme vzorec pre e-mailovú adresu pomocou
regulárneho výrazu a potom zadáme e-mailovú adresu, ktorú chceme overiť.
Pomocou funkcie re.match()
overíme, či zadaná e-mailová adresa
zodpovedá vzorcu.
Regex vždy formátujeme ako raw string
r""
. Tým zaistíme, že špeciálne sekvencie ako napr.
\n
nebudú plniť svoj špeciálny význam.
Validovať je možné čokoľvek - najmä formáty vstupov užívateľov. Teda e-mailové adresy, heslá, URL, formuláre a podobne.
Vyhľadávanie
Pomocou funkcie re.search()
vyhľadávame prvú časť reťazca,
ktorá zodpovedá regulárnemu výrazu. Všetky zodpovedajúce podreťazce
nájdeme pomocou funkcie re.findall()
a jednotlivé zhody pomocou
re.finditer()
.
Nasledujúci príklad analyzuje výskyt slova Ahoj
v texte:
import re text = "Ahoj, jak se máš? Já se mám moc dobře. Ahoj!" # Vyhledání první shody s regulárním výrazem match = re.search(r'Ahoj', text) if match: print("První shoda nalezena na indexu:", match.start()) # Vyhledání všech shod s regulárním výrazem matches = re.findall(r'Ahoj', text) print("Všechny shody:", matches) # Vyhledání všech shod s regulárním výrazem a vytištění jejich indexů for match in re.finditer(r'Ahoj', text): print("Shoda nalezena na indexu:", match.start())
Vo výstupe vidíme:
Výstup vyhledávání:
První shoda nalezena na indexu: 0
Všechny shody: ['Ahoj', 'Ahoj']
Shoda nalezena na indexu: 0
Shoda nalezena na indexu: 39
V tomto príklade vyhľadávame slovo Ahoj
v texte pomocou
regulárneho výrazu r'Ahoj'
. Funkcia re.search()
nájde prvú zhodu a vráti objekt Match
, ktorý obsahuje
informácie o zhode. Funkcia re.findall()
vráti zoznam všetkých
zhôd a funkcia re.finditer()
vráti iterovateľný objekt, ktorý
umožňuje prechádzať všetky zhody v reťazci. V tomto prípade vypisujeme
indexy všetkých zhôd v reťazci.
Nahrádzanie
Nahradenie časti reťazca vykonáme pomocou funkcie re.sub()
.
Nahradená časť musí zodpovedať regulárnemu výrazu. Pozrime sa na
príklad:
import re text = "Ahoj, jak se máš? Já se mám moc dobře. Ahoj!" # nahrazení slova "Ahoj" slovem "Nazdar" vystup = re.sub(r'\bAhoj\b', 'Nazdar', text) print(vystup)
Vo výstupe vidíme:
Výstup nahrazení:
Nazdar, jak se máš? Já se mám moc dobře. Nazdar!
Nastavenie správania
Regulárne výrazy je možné upraviť pomocou tzv. flagov, ktoré určujú
ich správanie. Ak potrebujeme použiť viac flagov naraz, reťazíme ich
pomocou operátora |
. Medzi najčastejšie používané patria:
re.IGNORECASE
- ignoruje veľkosť písmen,re.DOTALL
- dot (bodka) zodpovedá aj značkám konca riadku,re.MULTILINE
- hranice riadkov sú definované značkami začiatku a konca riadku,re.VERBOSE
- umožňuje písať regulárne výrazy vo viacerých riadkoch as komentármi,re.DEBUG
- zobrazí ladiace hlášky týkajúce sa spracovania regulárneho výrazu.
Funkcia re.compile()
Než sa pozrieme na príklad s flagmi, vysvetlíme si ešte funkciu
re.compile()
. Funkcia z modulu re kompiluje regulárny výraz do
objektu triedy SRE_Pattern
. Tento objekt používame na
vyhľadávanie, nahradzovanie alebo rozdelenie textu pomocou regulárneho
výrazu.
Funkcia re.compile()
má nasledujúcu syntax:
re.compile(pattern, flags=0)
Parameter pattern
je regulárny výraz, ktorý chceme
skompilovať. Parameter flags
(pozri vyššie) je voliteľný.
Pozrime sa na príklad:
import re text = """ Ahoj, jak se máš? Já se mám moc dobře. Nevolal jsem o pomoc. Ahoj! """ # Vytvoření regulárního výrazu pro hledání slova "moc" vzor = re.compile(r""" \bmoc\b # hledá slovo "moc" s ohledem na hranice slov """, re.IGNORECASE | re.VERBOSE) # Získání všech shod ve vstupním textu shody = vzor.findall(text, re.MULTILINE | re.DOTALL) # Výpis všech shod print(shody)
Vo výstupe vidíme:
Použití flagů:
['moc']
V tomto príklade použijeme flagy re.IGNORECASE
,
re.VERBOSE
, re.MULTILINE
a re.DOTALL
.
Regulárny výraz hľadá slovo moc
s ohľadom na hranice slov
(\bmoc\b
). Funkcia re.compile()
slúži na vytvorenie
regulárneho výrazu, ktorý je možné použiť opakovane. Funkcia
findall()
vráti všetky zhody vo vstupnom texte. Flag
re.MULTILINE
určuje, že hranice riadkov sú definované značkami
začiatku a konca riadku, a re.DOTALL
určuje, že dot (bodka)
zodpovedá aj značkám konca riadku.
V nasledujúcom kvíze, Kvíz - Iterátory, generátory a regexy v Pythone, si vyskúšame nadobudnuté skúsenosti z predchádzajúcich lekcií.