Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

9. diel - Regulárne výrazy v Pythone Nové

V predchádzajúcom cvičení, Riešené úlohy k 2.-3. lekciu kolekcií v Pythone, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.

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}, kde X udáva počet opakovaní,
  • {X, Y}, kde X `je minimální a `Y 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é

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:

  1. Prvý znak je bodka - výraz zatiaľ splnený.
  2. Druhý znak je bodka - výraz zatiaľ splnený.
  3. Tretí znak je bodka - výraz zatiaľ splnený.
  4. Štvrtý znak je bodka - výraz zatiaľ splnený.
  5. Ž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 + 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
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 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).
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

# 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 "Hello"
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.
Ď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 = """
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 cvičení, Riešené úlohy k 7.-8. lekciu kolekcií v Pythone, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.


 

Predchádzajúci článok
Riešené úlohy k 2.-3. lekciu kolekcií v Pythone
Všetky články v sekcii
Kolekcia v Pythone
Preskočiť článok
(neodporúčame)
Riešené úlohy k 7.-8. lekciu kolekcií v Pythone
Článok pre vás napísal Karel Zaoral
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Karel Zaoral
Aktivity