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.