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 e-mailom.
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álny aY
maximálny počet opakovaní,- preddefinované kvantifikátory.
Príklad štyroch ľubovoľných znakov by sme teda zapísali napríklad takto:
^.{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 |
Zložené zátvorky nám zoskupujú určitú časť výrazu. Kvantifikátory sa vzťahujú na celý obsah zátvorky.
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é
Hello
= 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ý.
Ak reťazec obsahuje niečo navyše, prejde
rovnako. Riešenie tohto problému je však jednoduché. Jednoducho pred výraz
pridáme striešku ^
(AltGr +
9 + 4), ktorá zaistí, že na začiatku reťazca bude
testovaný text. Za výraz dáme dolár $
(AltGr + ô).
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šie konštrukcie
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) |
[a-z] | malé písmená |
[A-Z] | 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 |
Strieška ^
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 a*z
a A-Z
. Znaky sa
berú z ASCII tabuľky, takže napríklad č
už daný výraz
nesplní.
Escapovanie
Niekedy potrebujeme vo výraze použiť nejaký metaznak.
Treba chceme overiť, či užívateľ zadal hello|world
.
Jednotlivé špeciálne znaky musíme odescapovať, teda
predsadiť spätným lomítkom (AltGr + Q). Výraz potom
bude vyzerať nasledovne:
\(hello\|world\)
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).
Pozrime sa na príklad krátkeho skriptu v Pythone, ktorý používa regulárne výrazy na validáciu e-mailovej adresy:
import re # define the pattern for an e-mail address pattern = r'^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$' # specify the e-mail address to validate email = '[email protected]' # check if the e-mail address matches the pattern if re.match(pattern, email): print('The e-mail address is valid.') else: print('The e-mail address is not valid.')
Vo výstupe vidíme:
Output of the match() function:
The e-mail address is valid.
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 Hello
v texte:
import re text = "Hello, how are you? I'm doing very well. Hello!" # Find the first match using a regular expression match = re.search(r'Hello', text) if match: print("First match found at index:", match.start()) # Find all matches using a regular expression matches = re.findall(r'Hello', text) print("All matches:", matches) # Find all matches and print their indices for match in re.finditer(r'Hello', text): print("Match found at index:", match.start())
Vo výstupe vidíme:
Search output:
First match found at index: 0
All matches: ['Hello', 'Hello']
Match found at index: 0
Match found at index: 41
V tomto príklade vyhľadávame slovo Hello
v texte pomocou
regulárneho výrazu r'Hello'
. 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 = "Hello, how are you? I'm doing very well. Hello!" # replacing the word "Hello" with "Hi" output = re.sub(r'\bHello\b', 'Hi', text) print(output)
Vo výstupe vidíme:
Replacement output:
Hi, how are you? I'm doing very well. Hi!
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 a s komentármi,re.DEBUG
- zobrazí ladiace hlášky týkajúce sa spracovania regulárneho výrazu.
Ďalšie flagy nájdeme v dokumentácii.
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 = """ Hello, how are you? I'm doing very well. I didn't call for help. Hello! """ # Create a regular expression to search for the word "very" pattern = re.compile(r""" \bvery\b # searches for the word "very" considering word boundaries """, re.IGNORECASE | re.VERBOSE) # Get all matches in the input text matches = pattern.findall(text, re.MULTILINE | re.DOTALL) # Print all matches print(matches)
Vo výstupe vidíme:
Using flags:
['very']
V tomto príklade použijeme flagy re.IGNORECASE
,
re.VERBOSE
, re.MULTILINE
a re.DOTALL
.
Regulárny výraz hľadá slovo very
s ohľadom na hranice slov
(\bvery\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í.