Regulární výrazy jsou vynálezem amerického matematika Stephena Kleene a troufám si tvrdit, že jsou starší než většina čtenářů La Trine. Pro nezasvěcené působí jako tajemné formule s magickou silou. Zdrojů, ze kterých se dají vědomosti o výrazech získat, je dost. Od vyčerpávající nápovědy v PHP, přes články až po knihy.
Člověk omámený kouzlem regulárních výrazů často propadne jejich nadužívání. Proto je škoda, že neexistují i tituly jako „Deset případů, kde se regexp absolutně nehodí“ nebo „Zpověď programátora: Už týden jsem nepoužil regulární výraz“ 🙂
Nebudu zde vysvětlovat principy regulárních výrazů – všechny zájemce bych rád odkázal na seriál Miroslava Pecky, který právě vychází na Intervalu. Protože jsme v něm narazil na určitou nesrovnalost, připojuji tuto svou korekturu.
Kde se vloudila chyba?
V části věnované subvýrazům a zpětným
referencím autor uvádí, že zpětné reference se zapisují ve tvaru
\\n
, kde n je číslo subvýrazu. K tomu mám vážnou
námitku: zapisují se ve tvaru \n
.
Svá slova potvrzuji tímto příkladem. Jasně
demonstruje, že při užití \2 \1
vše funguje dle očekávání,
zatímco \\2 \\1
ke zdárnému cíli nevede. Tedy rozdíl v jednom
lomítku je skutečně zásadní.
Poznámka: V regulárních výrazech nesmírně záleží na každém znaku, včetně mezer, a tudíž není možné tolerovat jakoukoliv nejasnost. Hledání chyb ve výrazech je mravenčí práce a může vést až k nervovým kolapsům včetně nepříjemného regurgitačního uvolnění organismu.
Něco tu nehraje
Co je zajímavé, příklady uvedené v článku Miroslava Pecky skutečně fungují, i s oním dvojitým lomítkem. Jak je to možné? Je to díky určité shodě okolností.
Každý programátor PHP by měl perfektně ovládat zápis řetězců. PHP k tomuto účelu nabízí hned tři způsoby, nejčastěji se používají tyto dva: uvození řetězce do jednoduchých a dvojitých uvozovek. Důležité je vědět, že takto zapsaný řetězec ještě PHP určitým způsobem transformuje do finální podoby.
V těchto transformacích hrají důležitou roli právě zpětná lomítka.
Pohledem na příslušné místo v dokumentaci
PHP zjistíte, že
zápis "\50"
podléhá transformaci (viz escapování)
a PHP jej nahradí za znak s kódem 50 v osmičkové soustavě, což je
mimochodem levá závorka. Naopak při použití jednoduchých uvozovek
k transformaci nedojde:
echo "\50"; // vypíše (
echo "\\50"; // vypíše \50
echo '\50'; // vypíše \50
Z příkladu je vidět, že nechtěné transformaci se lze vyhnout zdvojením zpětného lomítka nebo (lépe) nahrazením dvojitých uvozovek za jednoduché.
A tím se dostáváme zpět ke kritizovaným zpětným referencím. Protože autor používá ve všech příkladech řetězce s dvojitými uvozovkami, musí zpětná lomítka zdvojovat. Tedy zdvojení si vynucuje vlastnost PHP, která s regulárními výrazy absolutně nesouvisí. Kdyby použil uvozovky jednoduché, zdvojovat lomítko není třeba (avšak nevadí to). Ve všech dalších případech (syntax heredoc, načítání z databáze nebo souborů, mnou uvedený příklad) už vadit bude a příklady přestanou fungovat.
Závěr: Doporučuji regulární výrazy zapisovat opatrně a nejlépe s použitím jednoduchých uvozovek.
Komentáře
pif #1
dalsi duvod proc pouzivat jednoduche uvozovky :))
Jakub Vrána #2
Já bych spíš napsal, že kdyby použil uvozovky jednoduché, tak by nevadilo, že lomítko není zdvojené.
Je to spíše filozofický problém, ale \ slouží k escapování i uvnitř apostrofů. Kromě samotného \ totiž escapuje i apostrof. Když za lomítkem nenásleduje escapovaný znak, tak se to jako záchrana přeloží na \ + původní znak.
Psát
'\\1'
je tedy podle mě správnější, protože skutečně chci vypsat zpětné lomítko a ne něco escapovat.Napsat, že zpětné reference se uvozují \\ je samozřejmě špatně, ale možná to pan Pecka napsal proto, aby začátečníkům nezamotal hlavu.
spud #3
Sorry za offtopic, ale jaky je treti zpusob zapisu retezce v PHP? Nejak me nic jinyho nez uvozovky dvojity/jednoduchy nenapada.
David Grudl #4
#3 spude, Je s odkazem uveden na konci článku, hledej HEREDOC.
Jakub Vrána #5
Chudák ten, kdo si to vezme k srdci a bude chtít zkontrolovat např. Windows cestu a použije
'~c:\\windows\\system~i'
(vědom si toho, že \w a \s jsou v regulárním výrazu speciální znaky). Co se stane? Dvojitá lomítka požere už PHP a na regulární výraz zbyde \w a \s, což jsou zkratky za znak pro slovo a pro bílý znak.David Grudl #6
#5 Jakube Vráno, je třeba zapsat
'~c:\\\\windows\\\\system~i'
, jinou cestu neznám. Ale nerozumím té narážce s chudákem a jeho srdcem.Jakub Vrána #7
#6 Davide Grudle, To „to“ v #5 Jakub Vrána odkazuje na „Kdyby použil uvozovky jednoduché, zdvojovat lomítko není třeba“, tedy citovaný text. Možná jsi citovaný text přehlédl.
David Grudl #8
Jakube, vím že v PHP jsi machr, nebude lepší celý problém vysvětlit začátečníkům, než se tu štengrovat mezi sebou?
Ty napadáš větu, že v zdvojovat lomítko není třeba, která však souvisí se zápisem řetězce
'\50'
. A tady skutečně není třeba nic zdvojovat.spaze #9
Bych to celé vyřešil tak, jak doporučují v manuálu u preg_replace:
Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.