Linux: Kniha kouzel, vanilková příchuť 1.17 (27. února 2022)
Veškerá moc příkazové řádky/příkazového řádku přehledně, pro začátečníky i pokročilé

14. Regulární výrazy

Řada 1.x vanilkové příchuti Linuxu: Knihy kouzel je od 1. října 2020 do 1. března 2023 ve stavu dlouhodobé pasivní údržby; nahlášené chyby budou opravovány, ale aktivní vývoj se již věnuje novější vývojové řadě určené pro novější verze operačního systému a programů. Pokud nejste vázáni na starší verze programů, doporučuji vyhledat novou verzi z aktivně vyvíjené vývojové řady.
syntaxe zpracování textu

1. Úvod

Regulární výrazy představují velmi silný nástroj k vyhledávání, analýze, filtrování, kontrole syntaxe, extrakci a transformaci textů a textových dat. Slouží k formálnímu popisu (obvykle nekonečné) množiny řetězců a následné vyhledávání řetězců z této množiny v textu. S takto vyhledanými řetězci (tzv. výskyty či shodami) můžeme dále pracovat.

Regulární výrazy se objevují se ve většině programovacích jazyků, ale také v textových editorech či manuálním nastavení e-mailových filtrů.

V Linuxu se bohužel vyskytují tři různé syntaxe regulárních výrazů – základní regulární výrazy, rozšířené regulární výrazy a regulární výrazy jazyka Perl. Z praktických důvodů považuji za nejdůležitější rozšířené regulární výrazy, a proto kdykoliv napíšu „regulární výraz“ bez dalšího upřesnění, mám na mysli rozšířený regulární výraz. Kde se od sebe syntaxe liší, bude to u zaklínadel upřesněno; kde není uvedena samostatná varianta pro Perl, platí pro Perl varianta pro rozšířený regulární výraz.

2. Definice

3. Zaklínadla

3/1 Jednotlivé znaky

konkrétní znak#1 (1)
znak
libovolný znak (rozšířený i základní/Perl)#2
.
(?:.|\n)
kterýkoliv z uvedených znaků#3 (2)
[znaky]
libovolný znak kromě uvedených#4
[^znaky]
všechny znaky po první výskyt některého z uvedených/případně až do konce řetězce#5
[^znaky]*[znaky]
[^znaky]*
bílý znak/nebílý znak#6
\s
\S
desítková číslice (rozšířený/základní/Perl)#7
[0-9]
[0-9]
\d
jiný znak než desítková číslice (rozšířený/základní/Perl)#8
[^0-9]
[^0-9]
\D
závorky „()[]{}“ (rozšířený/ základní)#9
[(][)]\[\]\{\}
[(][)]\[\]{}
libovolný alfanumerický znak, i národní abecedy (rozšířený/základní/Perl)#10
[[:alnum:]]
[[:alnum:]]
\w
×libovolný znak kromě alfanumerických (rozšířený/základní/Perl)#11
[^[:alnum:]]
[^[:alnum:]]
\W
libovolné písmeno, i národní abecedy#12
[[:alpha:]]
libovolné malé/velké písmeno, i národní abecedy#13
[[:lower:]]
[[:upper:]]

3/2 Kvantifikátory (operátory opakování)

jednou nebo vůbec (≤ 1)(rozšířený/základní)#1
atom?
atom\?
libovolněkrát (≥ 0)(rozšířený/základní)#2
atom*
atom*
jednou nebo víckrát (≥ 1)(rozšířený/základní)#3
atom+
atom\+
přesně N-krát (= N)(rozšířený/základní)#4
atom{N}
atom\{N\}
M- až N-krát včetně (M ≤ počet ≤ N)(rozšířený/základní)#5
atom{M,N}
atom\{M,N\}
minimálně M-krát (≥ M)(rozšířený/základní)#6
atom{M,}
atom\{M,\}
maximálně N-krát (≤ N)(rozšířený/základní)#7
atom{,N}
atom\{,N\}
snažit se opakovat co nejméně (nehladové prohledávání)(jen Perl)#8
atomkvantifikátor?

3/3 Operátor „nebo“

některý z podvýrazů (rozšířený/základní)#1
výraz 1[|další výraz]
výraz 1[\|další výraz]

3/4 Kotvy a hranice (pozice)

začátek testovaného řetězce (rozšířený i základní/víceřádkový režim/Perl)#1
^
\`
\A
konec testovaného řetězce (rozšířený i základní/víceřádkový režim/Perl)#2
$
\'
\z
začátek slova (rozšířený a základní/Perl)#3
\<
\b(?=\w)
konec slova (rozšířený a základní/Perl)#4
\>
\b(?<=\w)
začátek nebo konec slova (rozšířený/základní/Perl)#5
(\<|\>)
\(\<\|\>\)
\b
začátek/konec řádku#6

3/5 Seskupení

seskupení (rozšířený/základní)#1
(podvýraz)
\(podvýraz\)
seskupení bez zapamatování (jen Perl)#2
(?:podvýraz)
pojmenované seskupení (jen Perl)#3
(?<název>podvýraz)

3/6 Paměť (omezená podpora)

původní podřetězec odpovídající celému regulárnímu výrazu (rozšířený a základní/Perl)#1 (3)
&
$&
záchyt – podřetězec původního řetězce odpovídající seskupení (varianty)#2 (4)
\pořadové-číslo-1-až-9⊨ v reg. výrazu: GNU sed a Perl; v řetězci náhrady: GNU sed
\\pořadové-číslo-1-až-9⊨ v řetězci náhrady: GNU awk (jen funkce gensub())
$pořadové-číslo-1-až-9⊨ v řetězci náhrady: Perl
totéž, ale první písmeno malé/velké#3 (5)
\l\pořadové-číslo-1-až-9\E
\u\pořadové-číslo-1-až-9\E
totéž, ale celý text malými/velkými písmeny#4 (6)
\L\pořadové-číslo-1-až-9\E
\U\pořadové-číslo-1-až-9\E
záchyt v Perlu v rámci regulárního výrazu (číslovaný/pojmenovaný)#5
\g{pořadové-číslo}
\g{název}

3/7 Vyhlížení (jen Perl)

ověřit, že za aktuální pozicí následuje shoda s daným regulárním podvýrazem#1
(?=podvýraz)
ověřit, že za aktuální pozicí nenásleduje shoda s daným regulárním podvýrazem#2
(?!podvýraz)
ověřit, že aktuální pozici předchází shoda s daným regulárním podvýrazem#3
(?<=podvýraz)
ověřit, že aktuální pozici nepředchází shoda s daným regulárním podvýrazem#4
(?<!podvýraz)

4. Parametry příkazů

4/1 bash

[[ řetězec =~ regulární-výraz ]]

Poznámka: Protože pravidla odzvláštňování regulárního výrazu v této konstrukci jsou neintuitivní a nepraktická, striktně doporučuji zadávat regulární výraz jako proměnnou, např. takto:

if [[ "$1/$2" =~ $regex ]]

Pozor! Proměnnou s regulárním výrazem v této konstrukci nikdy neuzavírejte do uvozovek! Pokud to uděláte, bash ji bude interpretovat jako obyčejný řetězec, ne jako regulární výraz!

Existuje ještě druhý přiměřeně funkční způsob:

[[ řetězec =~ $(printf %s "regulární výraz") ]]

Ale v tomto případě nesmí regulární výraz končit znakem nového řádku \n, protože ten by se při rozvoji ztratil; pokud tímto znakem končit musí, pomůže uzavřít ho do hranatých závorek („[\n]“).

4/2 egrep

egrep parametry [-e] 'regulární výraz' [soubor]
-vLogická negace; hledat řádky, které nevyhovují výrazu.
-xRegulárnímu výrazu musí odpovídat celá řádka (výchozí chování: jakýkoliv podřetězec řádku).
-zŘádky vstupních souborů jsou ukončeny nulovým bajtem; znak \n bude považovat za za normální znak.
-C počet„kontext“ Kromě vyhovujícího řádku vypíše zadaný počet předchozích a následujících. (Samostatně lze tyto počty nastavit parametry -A-B.)
-oMísto celých řádek vypisuje jednotlivé podřetězce vyhovující výrazu, každý podřetězec na samostatnou řádku.
-hVyhledává-li se ve více souborech, neuvede se jako prefix řádky název souboru.
-HVždy uvede jako prefix řádku název souboru.
-nJako prefix bude vypisovat číslo řádky.
-qŽádný normální výstup, jen otestuje, zda by našel alespoň jeden vyhovující řádek. Parametr -s zase potlačí chybová hlášení.
-m NUkončí hledání po nalezení N vyhovujících řádek.
-iNerozlišovat velká a malá písmena.

Poznámka: příkaz „grep“ má tytéž parametry jako „egrep“, ale pracuje se základními regulárními výrazy.

4/3 gawk

gawk [parametry] '/regulární výraz/[{příkazy}]' soubor
-F hodnotaNastaví systémovou proměnnou „FS“ (field separator) na uvedenou hodnotu.
-v proměnná=hodnotaNastaví proměnnou na uvedenou hodnotu.
-SSpustí skript v „bezpečném režimu“, kdy nemůže volat příkazy bashe, spouštět jiné programy ani otevírat další soubory.

4/4 perl

perl -nwe 'if ($_ =~ /regulární výraz Perlu/) {print $_}' <vstupní-soubor
perl -pwe 's/regulární výraz Perlu/výraz náhrady/[g]' <vstupní-soubor
-nVykoná program v cyklu pro každou řádku vstupu.
-pVykoná program v cyklu pro každý řádek vstupu a na konci každého cyklu vypíše proměnnou „$_“ ($ARG).
-wZapne užitečná varování. (-W zapne všechna varování.)
-e programVykoná tento program místo načtení programu ze souboru.
-XVypne všechna varování.

4/5 sed

sed parametry [[-e příkazy] -e] příkazy [vstupní-soubor]
-EPoužívá rozšířené regulární výrazy místo základních.
-i„in-place“ Výstupem přepíše původní soubor.
-zŘádek končí nulovým bajtem, ne znakem \n.
-u„unbuffered“ Čte a zapisuje data po jednotlivých řádcích. (Normálně je kvůli výkonu načítá po delších blocích.)

5. Instalace na Ubuntu

Příkazy „egrep“, „grep“, „perl“ a „sed“ jsou základními součástmi Ubuntu. Příkaz „gawk“ je nutné doinstalovat, nebo místo něj použít méně schopný příkaz „awk“, který je základní součástí Ubuntu.

sudo apt-get install gawk

Regulární výrazy jsou používány i v mnoha dalších programech.

6. Tipy a zkušenosti

7. Další zdroje informací

Pro samotné regulární výrazy je k dispozici velké množství webových stránek (viz Odkazy), ale většinou jsou zbytečné, protože s referenční příručkou (resp. s touto kapitolou) budete pravděpodobně schopen/a požadovaný regulární výraz vymyslet sám/a.

Pro zmíněné programy:

egrep --help
man gawk
perl --help
1 Některé znaky musejí být v regulárních výrazech pro zbavení svého speciálního významu odzvláštněny zpětným lomítkem.
2 Uvnitř těchto hranatých závorek se speciální znaky neodzvláštňují zpětným lomítkem, ale uvedením na určitou pozici.
3 Platí jen v rámci řetězce náhrady, ne v samotném regulárním výrazu.
4 Zdvojení zpětného lomítka v GNU awk vyplývá ze skutečnosti, že ho (obvykle) zadáváte jako řetězec v programovacím jazyce. Pokud byste náhodou např. načítali řetězec náhrady ze souboru, bude tam zpětné lomítko patřit pouze jedno!
5 Tuto variantu podporuje pravděpodobně jen Perl a sed a smí se vyskytnout pouze v řetězci pro náhradu, nikoliv přímo ve vlastním regulárním výrazu.
6 Viz poznámku k předchozímu zaklínadlu.
MarkdownSystémSpráva uživatelských účtů