Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!
Zadejte Vaši e-mailovou adresu:
Kamarád fotí rád?
Přihlas ho k odběru fotomagazínu!
Zadejte e-mailovou adresu kamaráda:
Informace
Obcování s ďáblem 20: Regulární výrazy se zpětnými odkazy
6. prosince 2001, 00.00 | Dnes uzavřeme tuto část teorie o používání UNIXu. Poslední finta regulárních výrazů, jíž se budeme podrobněji věnovat, jsou zpětné odkazy.
Regulární výrazy se zpětnými odkazyPoslední finta regulárních výrazů, jíž se budeme podrobněji věnovat, jsou zpětné odkazy.
Připomeňme jeden z příkladů, jež jsme si ukazovali na začátku jako problémy, jež lze s využitím regulárních výrazů snadno řešit:
"Představte si, že máte rozsáhlý projekt, ve kterém se v mnoha zdrojových souborech používá volání funkce "ellipse(x,y,r1,r2)" — kde samozřejmě x, y, r1 a r2 jsou obecné výrazy, určující střed elipsy a oba její poloměry. Na nových knihovnách se třeba objeví nová služba "circle(r,x,y)", která je mnohem efektivnější; chtěli bychom proto předělat všechna volání "ellipse" ve kterých je r1 stejné jako r2 na volání "circle" — nejenže musíme ověřit, zda je r1 a r2 stejné, ale navíc musíme změnit pořadí argumentů a jeden z nich vypustit."
Soustřeďme se zatím na vyhledání textu "ellipse(x,y,r1,r2)" ve zdrojových textech. Většinu už bychom toho uměli: na místě výrazů x, y, r1 a r2 prostě použijeme regulární výrazy ".*" (jistě, šlo by to i lépe, ale zatím si vystačíme s jednoduchým řešením). Výsledný regulární výraz by tedy mohl být "ellipse(.*,.*,.*,.*)"...
...ale ouha! Takovýto výraz nám najde i textové řetězce typu "ellipse(1,2,3,4)", a ty nechceme: zajímají nás pouze takové případy, kdy je r1 a r2 stejné. Co s tím? Je zřejmé, že potřebujeme zpětnou referenci typu "tady má být to samé, co je támhle".
Regulární výrazy naštěstí takového reference podporují; my se s nimi už vlastně jednou setkali, v příkladu "ls | egrep '^(.).*\1$'" ve dvanáctém dílu. Nyní se na ně podíváme podrobněji.
Zpětné odkazy
Součástí regulárních výrazů může být až devět zpětných odkazů. Samotný odkaz je representován prostě kombinací "\N", kde N je číslo odkazu 1-9; odkaz reprezentuje přesně stejný textový řetězec, který odpovídal regulárnímu výrazu uvnitř N-tého páru závorek.
Nyní si tedy již můžeme podrobně vysvětlit regulární výraz "^(.).*\1$", použitý ve dvanáctém dílu:
- "^": hned na začátku řádky...
- "(.)": ...je jeden znak (uzávorkování výrazu "." v tuto chvíli nehraje roli)...
- ".*": ...za nímž následuje cokoli...
- "\1": ...a pak je opět tentýž znak, se kterým jsme se setkali v bodě 2 (nyní se uzávorkování využije)...
- "$": ...a hned za ním už je konec řádku.
Už je asi také jasné, proč jsme zvolili egrep a ne grep: díky tomu, že egrep pracuje s rozšířenými regulárními výrazy, jsme si ušetřili několik zpětných lomítek. Příkaz grep by to se svými základními regulárními výrazy zvládl také, avšak odpovídající regulární výraz by byl o něco složitější: "^\(.\).*\1$" (kdo neví proč, ať si znovu přečte odstavec "Závorky" v minulém dílu!).
Popisovat řešení našeho problému s funkcí "ellipse" už je asi zbytečné — pozorní čtenáři už jistě vědí, jak na to. Proto jen pro kontrolu: zvolíme-li základní regulární výrazy, stačí pro vyhledání funkce, jež má oba poslední argumenty stejné, napsat "ellipse(.*,.*,\(.*\),\1)".
Záměny textových řetězců
Odkazy "\N" v regulárních výrazech se skvěle hodí i pro záměnu nalezeného textu jiným: často se nám stane, že uvnitř nového textového řetězce má zůstat nějaká část toho původního. S využitím klasického "find and replace" by to samozřejmě bylo nemožné; s regulárními výrazy není nic snazšího: stačí ve "vyhledávacím" výrazu požadovanou část uzávorkovat — a v textovém řetězci, jímž se nalezený text zaměňuje, použít odpovídající odkaz.
Pro příklad malinko předběhneme — ukážeme si řešení našeho problému (jímž je vyhledání funkcí "ellipse(x,y,r,r)" a jejich záměna funkcemi "circle(r,x,y)") s využitím standardního příkazu sed, který si podrobněji popíšeme až jindy. Pro dnešek se spokojíme s tím, že v podobě "sed -e '/<find>/s//<replace>/'" vyhledá výskyty regulárního výrazu "<find>" na standardním vstupu, a nahradí je textovým řetězcem "<replace>"; výsledek pak odešle na standardní výstup.
Nejprve si připravíme jednoduchá testovací data:
111 /tmp> cat > t
ellipse(1,2,3,4)
eclipse(1,2,3,3)
ellipse(5,6,7,7)
ellipse(moc,malo,argumentu)
ellipse(a,b+c,d-e+f*g,d-e+f*g)
112 /tmp>
Nyní použijeme příkaz sed s vhodnými regulárními výrazy pro hledání a záměnu:
112 /tmp> sed -e '/ellipse(\(.*,.*\),\(.*\),\2)/s//circle(\2,\1)/' < t
ellipse(1,2,3,4)
eclipse(1,2,3,3)
circle(7,5,6)
ellipse(moc,malo,argumentu)
circle(d-e+f*g,a,b+c)
113 /tmp>
Nejdřív se podíváme na vyhledávací regulární výraz, jímž je v příkazu sed řetězec "ellipse(\(.*,.*\),\(.*\),\2)". Už bychom mu měli rozumět: je to přesně to samé, čím jsme ukončili minulý odstavec, jen je navíc "zbytečně" uzávorkována část regulárního výrazu, jež odpovídá prvním dvěma parametrům.
Textový řetězec pro záměnu už je jednoduchý: je jím výraz "circle(\2,\1)", obsahující dva zpětné odkazy — první na poloměr (druhý pár závorek ve vyhledávacím výrazu), druhý na střed (druhý pár závorek).
To je pro dnešek vše
Příště se seznámíme trochu podrobněji s příkazy grep, fgrep a egrep, jež reprezentují asi nejpřímočařejší využití regulárních výrazů v unixu, a ukážeme si s nimi několik příkladů.
Obsah seriálu (více o seriálu):
- Obcování s ďáblem
- Obcování s ďáblem 2 - základy
- Obcování s ďáblem 3 - Práce se soubory
- Obcování s ďáblem 4 - Další práce se soubory
- Obcování s ďáblem 5 - Stále soubory, hlavně linky
- Obcování s ďáblem 6: Pár zbývajících drobností
- Obcování s ďáblem 7: Samá voda, přihořívá, hoří!
- Obcování s ďáblem 8: Jak se do shellu volá, tak se program ozývá
- Obcování s ďáblem 9: Nové finty na programy
- Obcování s ďáblem 10: Do fronty, pánové, do fronty!
- Obcování s ďáblem 11: Standardní vstup a výstup
- Obcování s ďáblem 13: Další triky
- Obcování s ďáblem 14: Vyšší škola hledání souborů
- Obcování s ďáblem 15: Příkaz find stokrát jinak
- Obcování s ďáblem 16: Co se ještě dá uvařit z příkazu find
- Obcování s ďáblem 17: Regulární výrazy
- Obcování s ďáblem 18: Speciální regulární výrazy
- Obcování s ďáblem 19: Skládání regulárních výrazů
- Obcování s ďáblem 20: Regulární výrazy se zpětnými odkazy
- Obcování s ďáblem 21:K čemu je dobrý grep...
- Zázraky ihned, nemožné na počkání: sed
- Obcování s ďáblem - další finty s příkazem sed
- Rozsáhlejší příklad se sedem
- Obcování s ďáblem: Další kouzla, aneb awk
- Awk a proměnné
- Obcování s ďáblem 27: Awk a výrazy
- Obcování s ďáblem: Awk a funkce
- Awk a příkazy
- Co je to vlastně "uživatel"?
- Vlastnictví objektů
- Přístupová práva
- Vlastník, skupina, ostatní...
- Jak je to se skupinami?
- Skupiny a uživatelé
- Scripty
- Komentáře, a volba shellu
- Pro skript může být shell cokoli!
- Shellové skripty a argumenty
- Skripty a proměnné: aritmetika
- Proměnné shellu, "dědění" hodnot
- Práce s proměnnými
- Práce se jmény souborů
- Pole hodnot
- Další triky kolem polí...
- Standardní proměnné shellu
- Základní příkazy pro skripty
- Příkaz if
- Speciální podmínkové příkazy
- Podmínky pro práci se soubory
- Jednoduchý cyklus
- Příkaz for a pomocné příkazy break a continue
- Příkaz case
- Příkazy exit a select
- Rejstřík a přehled
- Procesy
- Informace o procesech
- Další klíčová slova pro příkaz ps
- Příkaz ps: několik praktických přepínačů
- A k čemu že je "ps" dobré?
- Copak procesor, s pamětí je to horší
- Virtuální paměť
- A ještě jednou virtuální paměť
- Zpět k příkazu ps
- Skutečný žrout paměti
- Ještě jednou top
- Doplněk k topu: vm_stat
- Co to tedy všechno znamená?
- Nevychází nám dal a má dáti?
- Kam se stránky ukládají?
- Změna odkládacího disku
- Změna odkládacího disku / fstab
- Poslední poznámka k fstab
- A jak to je se soubory?
- Co vlastně příkaz lsof vypisuje?
- Příkaz lsof a obsah sloupce NAME
- SIPS - Terminál není jen pro nadšence UNIXu
- Tak nám zabili NetInfo, paní Müllerová
Tématické zařazení:
» Rubriky » Začínáme s