xom`s pinion - Tom Hnatovsky Blog

Nehladový regulární výraz v JavaScriptu

13. prosince 2006 Web design nekomentováno

Non 

Greedy regulární výrazy Regulární výrazy v JavaScriptu mají několik modifikátorů. No, několik, jsou tři:

  • i – ignorace rozlišování mezi velkými a malými písmeny (/strom/i vybere z textu jak „strom“ tak i „STROM“ nebo „Strom“)
  • g – globální hledání výskytu regulárního výrazu v celém řetězci (/strom/g vybere z textu všechny možné výskyty tohoto slova, bez g pouze ten první)
  • m – multi řádkování – dochází ke schodě kotvy ^ s $ na všech řádcích (normálně se ^ a $ chovají jako zástupné znaky pro počátek a konec řetězce, při použití modifikátoru m se označkují všechny počátky a konce řádků jako počátky a konce řetězce = /^a/g se na proměnné „aa\na“ provede právě jednou, přičemž /^a/gm dvakrát)

Jeden důležitý modifikátor mi však chybí – je jím určení, jestli se má regulární výraz chovat nenasytně, na což v praxi narazíme např. při výběru textu ze závorek..

Mějme text: „(tento text) a ještě jeden (textík)“ Pokud použijeme regulární výraz na výběr obsahu mezi závorkami, tak se nám vrátí obsah od první otevřené závorky po tu nejposlednější uzavřenou. Tudíž bude vrácená hodnota „tento text) a ještě jeden (textík“, ale to jsme nechtěli, chtěli jsme přeci vybrat obsah závorek!

Nenasytný výběr obsahu závorek by vypadal nějak následovně: /\((.)+\)/ - závorky patří mezi metaznaky, proto je musíme „oescapovat“ zpětným lomítkem, aby nabyly svého původního významu „pouhých“ závorek..

Existuje jednoduchý způsob jak toto chování potlačit – do definice regulárního výrazu vložíme znaky, které nesmí být v řetězci – v našem případě to jsou závorky.

Po úpravě omezující výběr závorek: /\(([^(\))^(\().])+\)/

Nyní se po provedení výrazu vybere obsah závorek zvlášť – při použití modifikátoru g ihned za sebou.. Jenže představme si případ, kdy máme více vnořených závorek – například: „(tento text) a ještě (jeden (textík))“

Náš upravený výraz vyhledává text v závorkách, které neobsahují závorky, tudíž by nedokázal vybrat obsah té složené „(jeden (textík))“ – vybral by pouze tu vnitřní závorku „textík“.

Mým řešením je zpracování výběru nějakou další funkcí, která změní závorky na nějaký jiný zástupný znak – třeba na definice entitních znaků a vrátí zbývající text k opětovnému zpracování regulárního výrazu – vlastně se jedná o iterační smyčku. Stejnak se podobné zpracování hodí právě k záměně či uvození vybraných částí s kontrolou četnosti otevírajících a uzavírajících znaků.. Můžeme si náš pokus ukázat na úkolu, kdy potřebujeme převést závorky třeba na divy.. Ukažme si to na kusu kódu:

Deklarujme si proměnnou opakovat globálně, abychom k ní mohli přistupovat nezávisle na jednotlivých instancích spuštěných funkcí. Základní hodnotou budiž false, což přerušuje iteraci. var opakovat = false; function test (p) { opakovat = false; Náš regulární výraz v akci p = p.replace(/\(([^(\()^(\)).])+\)/g, zavorkyNaDivy); Ve funkci zavorkyNaDivy se můžeme dočkat změny globálně deklarované proměnné opakovat.. * if (opakovat == true) { test(p); } } function zavorkyNaDivy (textik) { Definujme náhradu na počátku ^ a na konci $ řetězce. textik = textik.replace(/^\(/g, '\'); textik = textik.replace(/\)$/g, '\<\/div\>'); Zkontrolujme, zda-li po změně není potřeba ještě něco zpracovat. opakovat = true; return textik; } test(" (tento text) a (ještě (jeden (textík))) ");

* Proměnnou opakovat by šlo vynechat, pokud bychom ve funkci zavorkyNaDivy rovnou přistupovali k upravovanému textu globálně, potom by stačilo před návratem hodnoty zavolat test(), bez proměnné, která by v daném příkladě byla globální. Pokud tomu tak není, tak by se nám funkce zacyklily, protože by neustále přistupovaly k neupravenému textu..

Výsledkem použití popsaného algoritmu je text závorek prostý, obsahující nekřížené divy ohraničující bývalé uzávorkování. Každá špatně otevřená nebo uzavřená závorka zůstává v textu zachována..

Živá ukázka shrnující celý článek i po praktické stránce.

Poznámka: V článku popisuji možnosti výměny závorek za jiné značky, a proto si v regulárním výrazu vynucuji nepřítomnost otevřené i uzavřené závorky ve vybraném textu, ale jaké je překvapení, že k funkčnosti nehladového výběru stačí definovat pouze zákaz otevřené závorky. /\(([^(\().])+\)/ vybere z textu „(něco))” namísto očekávaného „(něco))“ pouze „(něco)“.. při použití jiných znaků tomu tak není, proto jsem poukazoval na deklaraci negace uzavírajícího i končícího znaku. Mimochodem je, pro mě, zajímavé, že se chovají stejně velkoryse k závorkám všechny aktuální verze velké trojky prohlížečů.

Komentovat

Článek zatím nebyl komentován. Podělte se svým názorem.

Pole komentáře: zmenšit / zvětšit

Jméno:

Email: (Gravatar ID)

Web:

Barva trávy (otázka proti robotům):

© 2004-2012 Tom Hnatovsky - Všechna práva vyhrazena