Regulárny výraz je malý jazyk na opis textového vzoru. Dokáže nájsť číslo faktúry, rozpoznať tvar dátumu, vybrať pole z logu alebo zjednotiť medzery. Pôsobí nečitateľne, pretože niekoľko interpunkčných znakov nesie veľa významov. Tajomstvo porozumenia nespočíva v zapamätaní celého reťazca, ale v čítaní zľava doprava: každý token hovorí enginu, aký znak, pozíciu alebo skupinu môže očakávať ďalej.

Literál zodpovedá sám sebe

Väčšina písmen a číslic hľadá presne daný znak. Vzor konto nájde túto postupnosť. Bodka, hviezdička, zátvorky a ďalšie metaznaky menia správanie. Ak majú byť doslovné, potrebujú escape.

Napríklad \. hľadá bodku, zatiaľ čo neescapovaná bodka obyčajne prijme takmer ľubovoľný znak. Význam backslashu môže navyše ovplyvniť string literal hostiteľského jazyka.

Character class opisuje jednu pozíciu

[abc] prijme jedno písmeno zo zoznamu, nie celé slovo. Rozsah [0-9] opisuje číslicu a negovaná class znak mimo množiny. Shorthand ako \d či \s môže podľa enginu a Unicode režimu zahŕňať viac než ASCII.

Alternatíva celých slov patrí do skupiny, napríklad (pes|mačka). Zameniť class za zoznam slov je častý zdroj príliš širokého matchu.

Quantifier riadi opakovanie

Hviezdička povoľuje nula alebo viac výskytov, plus aspoň jeden a otáznik robí časť voliteľnou. Zložené zátvorky vyjadrujú presný alebo obmedzený počet. Quantifier sa vzťahuje na bezprostredne predchádzajúci token či skupinu.

Greedy verzia najprv spotrebuje maximum a pri zlyhaní vracia znaky. Lazy verzia začne minimom. Správna voľba vychádza z hranice dát, nie z pravidla, že kratší match je vždy bezpečnejší.

Anchors opisujú pozíciu bez spotreby

Začiatok a koniec vstupu, word boundary alebo lookaround nekonzumujú znak. Validácia celej hodnoty obyčajne potrebuje anchors; vyhľadávací pattern ich naopak často nechce.

Multiline flag môže zmeniť začiatok a koniec na hranice jednotlivých riadkov. Pattern nemožno správne pochopiť bez flags a API, ktoré ho vykonáva.

Skupiny organizujú a zachytávajú

Zátvorky spájajú tokeny pre quantifier a alternatívu. Capturing group uloží nájdený text pre extrakciu alebo replacement. Named group ako year je odolnejšia než číselná pozícia.

Non-capturing group poskytne štruktúru bez zmeny číslovania. Zbytočné captures zhoršujú čitateľnosť a vytvárajú krehkú väzbu na spotrebiteľa.

Flags sú súčasťou zmluvy

Case-insensitive, multiline, dot-all, global a Unicode režim menia výsledok. Rovnaký source pattern môže v inom nastavení hľadať úplne iné hranice.

JavaScript, PCRE, Python, Java a .NET podporujú odlišné lookbehind, property classes a replacement syntax. Regex z online testera sa musí skúsiť v skutočnom runtime.

Lookaround kontroluje okolie

Lookahead a lookbehind vyžadujú kontext, ale nezahrnú ho do výsledku. Sú praktické pri pozičných podmienkach, no môžu znížiť prenositeľnosť a zvýšiť komplexitu.

Ak niekoľko negatívnych assertions simuluje business pravidlá, je často čitateľnejšie najprv extrahovať štruktúru a zvyšok overiť obyčajným kódom.

Replacement má vlastnú syntax

Náhradný string interpretuje group references, doláre a backslash. Správny search pattern preto ešte nezaručuje správny výsledok. Test má porovnať celý transformovaný text.

Nedôveryhodnú replacement hodnotu je bezpečnejšie vložiť callbackom alebo API pre literal string, aby sa náhodne nerozbalili odkazy na skupiny.

Regex nie je parser každého jazyka

Výborne funguje pre lokálnu, obmedzenú štruktúru. Hlboko vnorené HTML, komplikovaný programovací jazyk alebo validácia závislá od databázy potrebuje parser a explicitnú logiku.

Regex môže overiť rozumný tvar e-mailu, nie existenciu schránky. Môže nájsť dátum, nie potvrdiť kalendárnu platnosť.

Operácia určuje význam výsledku

Hľadanie prvého matchu, všetkých matchov a validácia celého vstupu sú rozdielne zmluvy. Kód má pomenovať zámer a riešiť žiadny aj viacnásobný výsledok.

Dobrý výraz má príklady pozitívnych a negatívnych hodnôt, limit vstupu a vysvetlenie každej časti. Keď sa dá čítať token po tokene a preložiť do bežných viet, prestáva byť interpunkčnou hádankou.

Unicode mení predstavu o jednom znaku

Používateľ môže vnímať písmeno s diakritikou alebo emoji ako jeden znak, hoci Unicode reprezentácia obsahuje viac code points. Bodka alebo jednoduchý quantifier preto nemusí zodpovedať tomu, čo rozhranie počíta ako jednu viditeľnú pozíciu. Kombinujúce znamienka, surrogate páry a grapheme clusters potrebujú podporu konkrétneho enginu alebo samostatnú Unicode knižnicu.

Class [A-Za-z] opisuje iba úzky ASCII rozsah a pri menách či mestách odmietne legitímne údaje. Unicode property ako letter môže byť vhodnejšia, no stále neodpovedá na doménovú otázku, ktoré znaky produkt skutočne povoľuje. Normalizácia NFC alebo NFKC je oddelené rozhodnutie a nemá sa vykonávať náhodne počas matchingu.

Search engine môže nájsť viac než autor očakáva

Global search sa po každom matchi posúva ďalej. Pattern schopný prázdneho matchu potrebuje pravidlo, aby sa loop nezastavil na rovnakej pozícii. Knižnice sa v tomto správaní líšia. Overlap matches tiež nemusia byť vrátené automaticky, hoci doména ich potrebuje.

Extrakčný kód má kontrolovať počet výsledkov, nie iba prvý. Ak dokument podľa zmluvy obsahuje presne jeden identifikátor, druhý výskyt je validačná chyba, nie dôvod potichu vybrať prvý. Pomenovanie funkcie findFirst, findAll alebo validateWhole zviditeľní očakávanie.

Regex a parser sa môžu rozumne kombinovať

Pattern môže lacno nájsť kandidátne riadky alebo tokeny a štruktúrovaný parser potom overí celý význam. Pri logu regex identifikuje prefix a delimiter, kód skonvertuje dátum, číslo a enum. Také rozdelenie udrží pattern lokálny a poskytne kvalitnejšie chyby.

Naopak používať regex na HTML, JSON alebo SQL iba preto, že vstup vyzerá jednoducho, ignoruje escaping, vnorenie a error recovery. Existujúci parser pozná gramatiku a bezpečnostné okraje lepšie než rastúci zoznam výnimiek.