# Regulárne výrazy

     Tento dodatok obsahuje krátky, ale snáď dostatočný
    úvod do sveta regulárnych výrazov.
    Popisuje regulárne výrazy tak, ako ich používa &kate;.
    Tie sa líšia od regulárnych výrazov jazyka Perl aj od
    regulárnych výrazov príkazu grep.

## Úvod

Regulárne výrazy umožňujú popísať nejaký text tak, aby ho bolo možné nájsť v texte aj v prípade, že to nie je vždy rovnaký text.

Napríklad: Povedzme, že chceme nájsť text v odstavcoch, ktoré začínajú menami Henrik alebo Pernille a za nimi bude nejaký tvar anglického slovesa say.

Normálne by ste hľadali najprv prvé meno Henrik, možno ešte s kúskom sa, asi takto: `Henrik sa` a každý nájdený výskyt by ste skontrolovali, či je na začiatku odstavca a či za písmenami sa slovo pokračuje says, said a tak podobne. No a potom by vás to isté čakalo v druhým menom...

Pomocou regulárnych výrazov sa to dá urobiť jediným hľadaním a oveľa presnejšie.

Aby sme to dosiahli, regulárne výrazy definujú pravidlá pre vyjadrenie detailov ale aj zobecnení textu. Náš príklad môžeme vyjadriť takto: Riadok začína buď Henrik alebo Pernille (za nimi môžu byť až 4 medzery alebo tabulátory), za ktorými je prázdne miesto a potom sa. Hneď za tým je ys alebo id. Zapíšeme ho týmto regulárnym výrazom:

`^[ \t]{0,4}(Henrik|Pernille) sa(ys|id)`

Tento príklad ukazuje štyri hlavné koncepty moderných regulárnych výrazov:

- Vzorky

- Podmienky

- Kvantifikátory

- Spätné referencie

Znak `^` (caret) na začiatku výrazu predstavuje podmienku, ktorá platí iba v prípade, že text, ktorý odpovedá zvyšku výrazu, je na začiatku riadku.

Reťazce `[ \t]` a `(Henrik|Pernille) sa(ys|id)` sú vzorky. Prvý je trieda znakov, ktorá odpovedá medzere alebo horizontálnemu tabulátoru, druhá obsahuje najprv podvýraz pre `Henrik` alebo `Pernille`, potom kúsok zodpovedajúci práve textu `sa` a nakoniec podvýraz buď pre `ys` alebo `id`.

Reťazec `{0,4}` je kvalifikátor, ktorý hovorí niečo medzi 0 až 4 opakovaniami toho, čo bolo predtým.

Pretože reguálne výrazy podporujú koncept spätných referencií, môžete si zatvorením podvýrazu do zátvoriek uložiť nájdený text, je možné sa pri hľadaní na takto uložený text odvolávať.

Dohromady výraz nájde práve to, čo sme chceli.

Nasledujúce kapitoly detailne popisujú, ako vytvárať a používať vzorky, triedy znakov, podmienky, kvalifikátory a spätné referencie. Záverečná časť obsahuje niekoľko užitočných príkladov.

## Vzorky

Vzorky obsahujú reťazce a triedy znakov. Vzorky môžu obsahovať podvzorky, čo sú vzorky v zátvorkách.

### Zápis špeciálnych znakov (escaping)

Vo vzorkách a aj v triedach znakov majú niektoré znaky špeciálny význam. Aby ste ich mohli použiť priamo pre hľadanie, musia byť označené. Po anglicky sa tomu hovorí escaped. Softvér ich potom bude považovať za normálne znaky.

To sa urobí tak, že na začiatok pridáte znak `\` (spätné lomítko).

Softvér pre spracovanie regulárnych výrazov potichu ignoruje takto zadané znaky tak, že im nedáva žiadny špeciálny význam v danom kontexte. Preto je možné takto zapísať napríklad aj j (`\j`). Ak neviete, či náhodou znak nemá špeciálny význam, môžete ho kľudne takho zapísať.

### Triedy znakov a skratky

Trieda znakov je výraz, ktorý odpovedá jednému zo skupiny znakov. V regulárnych výrazoch sa definujú znaky, ktoré sú v triede, pomocou hranatých zátvoriek `[]` alebo pomocou niektorej zo skratiek uvedených nižšie.

Jednoduché triedy znakov obsahujú iba jeden alebo viac znakov, napríklad `[abc]` (nájde buď písmeno a, b alebo c) alebo `[0123456789]` (odpovedá nejakej číslici).

Pretože písmená a číslice sú usporiadané, môžete si ich zadanie skrátiť pomocou rozsahov: `[a-c]` je to isté ako `[abc]` a `[0-9]` znamená `[0123456789]`. Kombinácie, napríklad `[a-fynot1-38]` sú tiež povolené (tento príklad by samozrejme našiel a,b,c,d, e,f,y,n,o,t, 1,2,3 alebo 8).

Veľké písmená sú niečo iné ako malé písmená. Aby ste vytvorili tiedu, v ktorej sa veľkosť písmen nerozlišuje, musíte napríklad pre a a b použiť `[aAbB]`.

Je samozrejme možné vytvoriť aj obrátenú triedu, ktorá bude odpovedať všetkému, čo v triede nie je. Jednoducho pridajte na začiatok triedy `^`:

`[^abc]` nájde všetky znaky okrem a, b or c.

Okrem normálnych znakov sú šte definované skratky, aby sa vám zjednodušil život:

`\a`

  Toto odpovedá znaku zvonček z ASCII (BEL, 0x07).

`\f`

  Toto odpovedá znaku konca stránky ASCII (FF, 0x0C).

`\n`

  Toto odpovedá znaku koniec riadku z ASCII (LF, 0x0A, koniec riadku v systémoch Unix).

`\r`

  Toto odpovedá znaku presun na začiatok z ASCII (CR, 0x0D).

`\t`

  Toto odpovedá znaku horizontálny tabulátor z ASCII (HT, 0x09).

`\v`

  Toto odpovedá znaku vertikálny tabulátor z ASCII (VT, 0x0B).

`\xhhhh`

  Toto zodpovedá znaku Unicode, ktorého hexadecimálny kód je hhh (medzi 0x0000 až 0xFFFF). \0ooo (čiže \zero ooo) odpovedá znaku ASCII/Latin-1 s kódom v osmičkovej sústave ooo (medzi 0 a 0377).

`.` (bodka)

  Toto zodpovedá ľubovoľnému znaku (aj konca riadku).

`\d`

  Toto zodpovedá číslici. Rovnaké ako `[0-9]`

`\D`

  Toto zodpovedá niečomu inému než číslici. Rovnaké ako `[^0-9]` alebo `[^\d]`.

`\s`

  Toto zodpovedá znaku prázdneho miesta. Prakticky to isté ako `[ \t\n\r]`

`\S`

  Toto zodpovedá normálnemu znaku. Prakticky to isté ako `[^ \t\n\r]` a rovnaké ako `[^\s]`.

`\w`

  Zodpovedá ľubovoľnému znaku slova - v tomto prípade písmenu alebo číslici. Uvedomte si, že podtržítko(`_`) mu nezodpovedá (ako je to v jazyku Perl). Rovnaké ako `[a-zA-Z0-9]`

`\W`

  Zodpovedá znaku, ktorý nie je v slovách - všetko okrem písmen a číslic. rovnaké ako `[^a-zA-Z0-9]` alebo `[^\w]`

Skrátené triedy je možné vložiť do vlastných tried, napríklad pre nájdenie slova, medzery alebo bodky môžete použiť `[\w \.]`

Zápis POSIX tried, čiže `[:<meno triedy>:]` momentálne nie je podporovaý.

#### Znaky so špeciálnym významom v triedach znakov

Tieto znaky majú v rámci [] špeciálny výraz a ich je nutné doplniť o spätné lomítko v prípade, že ich chcete priamo zahrnúť do triedy:

`]`

  Ukončí aktuálnu triedu. Neusí byť so spätným lomítkom v prípade, že je to prvý znak triedy (prípadne hneď za `^`.

`^`

  Označuje zápornú triedu, ak je to prvý znak. Ak ho chcete priamo hľadať a uviesť ako prvý znak, musíte ho použiť so spätným lomítkom.

`-` (pomlčka)

  Obsahuje logický rozsah.

`\` (spätné lomítko)

  Znak pre escape znakov.

### Alternatívy: nájdenie jedno z

Ak chcete nájsť jednu z niekoľkých možností, môžete ich oddeliť pomocou `|` (znak vertikálnej čiary).

Napríklad pre nájdenie John alebo Harry môžete použiť výraz `John|Harry`.

### Pod-vzorky

Podvzorky sú vzorky v zátvorkách a používajú sa na niekoľko vecí.

#### Zadanie alternatív

Môžete ich použiť pre zadanie skupiny alternatívnych možností. Jednotlivé možnosti sa oddeľujú znakom |.

Napríklad pre nájdenie niektorého zo slov int, float alebo double môžete použiť vzorku `int|float|double`. Ak chcete nájsť iba jednu z týchto slov a za ním má byť medzera a nejaké písmená, uzavrite alternatívy do podvzorky: `(int|float|double)\s+\w+`.

#### Zachytenie nájdeného textu (spätné referencie)

Ak chcete používať spätné referencie, použite podvzorky na označenie časti, ktorú chcete zapamätať.

Napríklad, ak chcete nájsť dva výskyty jednoho slova oddelené čiarkou a prípadne nejakými medzerami, môžete napísať `(\w+),\s*\1`. Podvzorka `\w+` nájde zhluk písmen a celý výraz bude odpovedať ak za nimi bola čiarka, 0 alebo viac medzier a potom rovnaký zhluk znakov. (Reťazec `\1` označuje prvú podvzorku v zátvorkách)

Prečítajte si aj kapitolu Spätné referencie.

#### Dopredné podmienky

Dopredné podmienky sú podvzorky začínajúce `?=` alebo `?!`.

Napríklad, ak chcete nájsť Bill ale iba ak za ním nie je Gates, môžete použiť tento výraz: `Bill(?! Gates)`. (Toto nájde Bill Clinton a aj Billy the kid, ale ostatné výskyty to bude ignorovať.)

Podvzorky používané pre podmienky sa nepamätajú.

Prečítajte si aj kapitolu Podmienky.

### Znaky, ktoré majú špeciálny význam vo vzorkách

Vo vzorkách majú tieto znaky špeciálny význam, takže pre ich priame hľadanie ich musíte doplniť spätným lomítkom.

`\` (spätné lomítko)

  Znak pre escape.

`^`

  Podmienka pre začiatok reťazca.

`$`

  Podmienka pre koniec reťazca.

`()` (ľavá a pravá zátvorka)

  Označuje podvzorky.

`{}` (ľavá a pravá zložená zátvorka)

  Označuje číslené kvalifikátory.

`[]` (ľavá a pravá hranatá zátvorka)

  Označuje triedy znakov.

`|`

  Logické OR. Oddeľuje alternatívy.

`+` (plus)

  Kvalifikátor, 1 alebo viac.

`*` (hviezdička)

  Kvalifikátor, 0 alebo viac.

`?` (otáznik)

  Nepovinný znak. Dá sa chápať ako kvalifikátor 0 alebo 1.

## Kvantifikátory

Kvantifikátory umožňujú, aby regulárny výraz zodpovedal danému počtu alebo bol v danom rozsahu opakovaní znaku, triedy alebo podvzorky.

Kvantifikátory sú uzavreté v zložených zátvorkách (`{` a `}`) a majú tvar `{[minimálne-výskytov][,[maximálne-výsktytov]]}`

Použitie sa najlepšie vysvetlí na príklade:

`{1}`

  Presne jeden výskyt

`{0,1}`

  Jeden alebo žiadny výskyt

`{,1}`

  To isté ale menej písania :-)

`{5,10}`

  Aspoň 5 ale maximálne 10 výskytov.

`{5,}`

  Aspoň 5 výskytov, žiadne obmedzenie zhora.

Okrem toho existujú aj skratky:

`*` (hviezdička)

  podobné ako `{0,}`, nájde ľubovoľný počet opakovaní.

`+` (plus)

  podobné ako `{1,}`, aspoň jeden výskyt.

`?` (otáznik)

  podobné ako `{0,1}`, 0 alebo 1 výskyt.

### Greed

Ak používate kvantifikátory bez maximálnej hodnoty, regulárne výrazy sa štandardne snažia nájsť čo najviac zodpovedajúceho textu. Tomu sa často hovorí greedy chovanie.

Moderné regulárne výrazy poskytujú spôsob, ako toto chovanie vypnúť. Napríklad v dialógu pre hľadanie je voľba Minimálne hľadanie, ktoré označuje, či sa má hľadať takto maximalisticky.

### Príklady zo života

Tu je pár príkladov využitia kvantifikátorov

`^\d{4,5}\s`

  Zodpovedá čísliciam v 1234 go a 12345 now, ale nie v 567 eleven ani v 223459 somewhere

`\s+`

  Odpovedá jednému alebo viacerým prázdnym znakom

`(bla){1,}`

  Zodpovedá všetkým blablabla a bla v blackbird alebo tabla.

`/?>`

  Zodpovedá /> v <closeditem/> ako aj > v <openitem>.

## Podmienky

Podmienky umožňujú, aby regulárne výrazy zodpovedali iba za zadaných podmienok.

Podmienka nemusí zodpovedať znaku. Skôr overuje okolie, či v nom niečo platí. Napríklad hranica slov sa nesnaží nájsť písmeno nepatriace slovu na svojej druhej strane. Namiesto toho overí, že tam nie je znak slova. To znamená, že podmienka bude platiť aj tam, kde žiadny znak nieje, napríklad na konci prehľadávaneho reťazca.

Niektoré podmienky obsahujú vzorky, ktorým majú zodpovedať, ale nájdený text sa nestane súčasťou výsledku celého výrazu.

Regulárne výrazy, ktoré tu popisujeme, podporujú tieto podmienky:

`^` (začiatok reťazca)

  Zodpovedá začiatku prehľadávaného reťazca.

  Výraz `^Peter` bude zodpovedať Peter v reťazci Peter, hey!, ale nie v Hey, Peter!

`$` (koniec reťazca)

  Zodpovedá koncu prehľadávaného reťazca.

  Výraz `you\?$` nájde posledné you v reťazci You didn't do that, did you? ale žiadne v You didn't do that, right?

`\b` (okraj slova)

  Platí, ak je na jednej strane znak slova, ale na druhej nie.

  To sa hodí pre nájdenie koncov slov, napríklad na oboch koncoch slova musí platiť. Výraz `\bin\b` nájde samostatné in v reťazci He came in through the window, ale nie in v slove window.

`\B` (nie okraj slova)

  Platí, ak neplatí \b.

  To znamená, že bude napríklad zodpovedať v slovách: Výraz `\Bin\B` bude nájdený v window ale nie v integer alebo I'm in love.

`(?=VZORKA)` (Pozitívny výhľad)

  Podmienka výhľadu sa pozrie na reťazec, ktorý nasleduje za možným výskytom. Pozitívny výhľad zabráni, aby sa našiel text, ktorý by nezodpovedal VZORKA, ale text, ktorý vzorke zodpovedá, sa vo výsledku neobjaví.

  Výraz `auto(?=\w)` zodpovedá auto v autobus ale nie v To auto je pokazené.

`(?!VZORKA)` (Negatívny výhľad)

  Negatívny výhľad zabráni nájdeniu textu v prípade, že nasledujúci text nezodpovedá VZORKA

  Výraz `const \w+\b(?!\s*&)` bude zodpovedať na const char v reťazci const char* foo ale nie const QString v const QString& bar, pretože & zodpovedá vzorke negatívneho výhľadu.

## Spätné referencie