Deprecated: Function set_magic_quotes_runtime() is deprecated in /mnt/data/accounts/w/webmark/data/www/blog/textpattern/lib/txplib_db.php on line 14
Regulární výrazy a JavaScript (5) - ukázková aplikace :: Blog v pavučině
Blog v pavučině je mrtev. Ať žije nový blog Všeho s Mírou
Skočit na obsah Skočit na menu Skočit na vyhledávání

Regulární výrazy a JavaScript (5) - ukázková aplikace

V předešlých článcích jsme si předvedli použití různých metod pro práci s regulárními výrazy v JavaScriptu. Proč si tedy nevytvořit malou webovou aplikaci?

Tato aplikace bude (skoro) všechny tyto metody (nevyužijeme pouze nejjednodušší dvě metody search() a test()) používat při práci s řetězci a regulárními výrazy…

Co bude naše aplikace umět?

  • najít části vstupního řetězce, které odpovídají regulárnímu výrazu a vypsat je jako seznam oddělený libovolným oddělovačem (použijeme match())
  • najít části vstupního řetězce, které odpovídají regulárnímu výrazu, zaměnit je za náhradu (s možností použití zpětné reference) a vrátit řetězec po provedení všech náhrad (použijeme replace())
  • rozdělit vstupní řetězce s použitím oddělovače popsaného pomocí regulárního výrazu a takto získané části spojit pomocí libovolného oddělovače do výstupního řetězce (použijeme split())
  • najít části vstupního řetězce, které odpovídají regulárnímu výrazu (a jeho subvýrazům), a vypsat je jako číslovaný seznam shod (formát připomínající dvourozměrné pole) (použijeme exec())

Vyzkoušejte si nejdříve hotovou aplikaci (zdrojový kód). Jak vidíte, aplikace obsahuje šest textových vstupních polí (regvyraz, modifikatory, oddelovac, nahrada, vstup, vystup). Ne všechna pole musí být vždy vyplněna – vždy záleží jakou akci (Match, Replace, Split, Exec) budeme chtít provádět. Podívejme se na jednotlivá pole:

  • Pole vstup obsahuje vstupní text (text, který chceme zpracovat).
  • Pole vystup obsahuje text, který příslušná funkce vrátí.
  • Pole regvyraz obsahuje regulární výraz zapsaný bez oddělovačů (/) a modifikátorů.
  • Pole modifikatory obsahuje řetězec složený z písmen patřičných modifikátorů (například g, gi a podobně).
  • Pole oddelovac je použito pouze při akci Match nebo Split a obsahuje oddělovač (respektive spojovací řetězec) jednotlivých částí.
  • Pole nahrada je použito jen při akci Replace a obsahuje řetězec, který se použije jako náhrada řetězce odpovídajícího regulárnímu výrazu.

Celá aplikace pracuje na velmi jednoduchém principu. Každé z tlačítek (akcí) spustí jednu ze čtyř uživatelsky definovaných funkcí (f_match(), f_replace(), f_split(), f_exec()). Každá funkce načte z polí formuláře vstupy, které použije jako argument příslušné funkce (metody) postavené na regulárních výrazech (match(), replace(), split(), exec()). U metod, které vrací pole (match(), split(), exec()), je návratová hodnota převedena na řetězec pomocí funkce join() (u akcí Match a Split) nebo pomocí procházení pole v cyklu a „ručního“ zřetězení prvků pole (u akce Exec).

Zdrojový kód stránky s formulářem bude vypadat následovně:

<html>
<head>
<meta http-equiv=„Content-Type“ content=„text/html; charset=windows-1250“/>
<meta http-equiv=„Content-language“ content=„cs“/>
<link rel=„stylesheet“ type=„text/css“ href=„reapp.css“/>
<title>Javascript RegExp All-in-1 Tool</title>
<script type=„text/ja­vascript“>

zde budou jednotlivé funkce (zdrojový kód viz níže)

</script>
</head>

<body>
<h1>Javascript RegExp All-in-1 Tool</h1>

<form id=„reapp“ name=„reapp“ action="" onsubmit=„return false;“>
<table>
<tr>
   <td class=„popis“>Re­gulární výraz</td>
   <td><input class=„txtinput“ type=„text“ name=„regvyraz“ /></td>
</tr>
<tr>
   <td class=„popis“>Mo­difikátory</td>
   <td><input class=„txtinput“ type=„text“ name=„modifikatory“ /></td>
</tr>
<tr>
   <td class=„popis“>Od­dělovač</td>
   <td><input class=„txtinput“ type=„text“ name=„oddelovac“ /></td>
</tr>
<tr>
   <td class=„popis“>Náh­rada</td>
   <td><input class=„txtinput“ type=„text“ name=„nahrada“ /></td>
</tr>
<tr>
   <td class=„popis“>Vstup</­td>
   <td><textarea name=„vstup“ cols=„60“ rows=„20“>
</textarea></td>
</tr>
<tr>
   <td class=„popis“>Výs­tup</td>
   <td><textarea name=„vystup“ cols=„60“ rows=„20“>
</textarea></td>
</tr>
<tr>
   <td class=„popis“>Ak­ce</td>
   <td>
      <input value=„Match“ type=„submit“ onclick=„f_match()“ />
      <input value=„Replace“ type=„submit“ onclick=„f_re­place()“ />
      <input value=„Split“ type=„submit“ onclick=„f_split()“ />
      <input value=„Exec“ type=„submit“ onclick=„f_exec()“ />
   </td>
</tr>
</table>
</form>

</body>
</html>

Ve výše uvedeném kódu jsou u některých elementů uvedeny CSS třídy odpovídající externí definici stylů, stylování stránky se však v tomto článku věnovat nebudeme. Výše uvedený zdrojový kód stránky neobsahuje vlastní javascriptové funkce – na ty se podíváme samostatně níže. V kódu stojí za pozornost ještě zápis <form id=„reap­p“ name=„reap­p“ action="" on­submit=„retur­n false;“>, respektive především akce onsubmit=„retur­n false;“, která zajistí, že kliknutí na tlačítka Match, Replace, Split či Exec (což jsou input prvky typu submit) nezpůsobí odeslání formuláře.

function f_match()
{
var vstup1=documen­t.reapp.vstup­.value;
var regvyraz1=new RegExp(documen­t.reapp.regvy­raz.value,docu­ment.reapp.mo­difikatory.va­lue);
var result=vstup1­.match(regvyraz1);
document.reap­p.vystup.valu­e=result.join(do­cument.reapp.od­delovac.value­);
};

Funkce f_match() je jednoduchá a snad by ani žádný komentář nevyžadovala. Přesto, pár slov se na tomto místě sluší. Vstupní text (řetězec, načtený z formuláře) si uložíme do proměnné vstup1, poté vytvoříme instanci objektu RegExpregvyraz1. Takto vzniklé proměnné použijeme pro metodu match(). Pole result, které metoda match() vrátí, převedeme pomocí metody join() na řetězec, který zobrazíme v prvku textarea.

function f_replace()
{
   var vstup1=documen­t.reapp.vstup­.value;
   var regvyraz1=new RegExp(documen­t.reapp.regvy­raz.value,docu­ment.reapp.mo­difikatory.va­lue);
   var result=vstup1­.replace(regvy­raz1,document­.reapp.nahrada­.value);
   document.re­app.vystup.va­lue=result;
};

Funkce f_replace() je velmi podobná. Dokonce je ještě jednodušší, protože metoda replace() vrátí přímo řetězec, který se zobrazí v textarea.

function f_split()
{
   var vstup1=documen­t.reapp.vstup­.value;
   var regvyraz1=new RegExp(documen­t.reapp.regvy­raz.value,docu­ment.reapp.mo­difikatory.va­lue);
   var result=vstup1­.split(regvyraz1);
   document.re­app.vystup.va­lue=result.jo­in(document.re­app.oddelovac­.value);
};

Funkce f_split() má analogickou strukturu jako f_replace(). Jediný (ale podstatný) rozdíl je v tom, že regulární výraz popisuje řetězec, pomocí nějž se má vstupní text (řetězec) rozdělit na části. Takto vzniklé části (pole řetězců) se opět převedou s použitím metody join() na výstupní řetězec.

function f_exec()
{
   var vstup1=documen­t.reapp.vstup­.value;
   var regvyraz1=new RegExp(documen­t.reapp.regvy­raz.value,docu­ment.reapp.mo­difikatory.va­lue);
   var i=0; //inicializace – počet nalezených shod
   var subvyrazy=""; //řetězec pro zapamatování výstupu
   while(resul­t1=regvyraz1.e­xec(vstup1))
   {
      for(var j=0;result1[j];j++)
         subvy­razy=subvyrazy­+„[“+i+„][“+j+„]: "+result1[j]+“\n";
      if(!reg­vyraz1.global) break; //opatření proti zacyklení
      i++; //inkrementace – počet nalezených shod
   };
   document.re­app.vystup.va­lue=subvyrazy;
};

Kód funkce f_exec() je velmi podobný kódu příkladu (u metody exec()) v předcházejícím článku. Tato funkce je přeci jen o něco složitější než tři předcházející, proto doporučuji si nejdříve vyzkoušet při jakých vstupech (regulární výraz, modifikátory, vstupní text) vrací jaký výstup (respektive především jak je výstup formátován).

Funkce je postavena na dvou vnořených cyklech. Vnější while cyklus slouží k opakovanému volání metody exec() při globálním prohledávání (počet průchodů cyklem zaznamenává počítadlo i). Vnořený cyklus for slouží k procházení shod s jednotlivými subvýrazy, tedy de facto pro procházení pole, které vrátí metoda exec() (počet průchodů tímto cyklem zaznamenává počítadlo j). V cyklu while voláme opakovaně result1=regvy­raz1.exec(vstup1). Navrácené pole result1 procházíme ve for cyklu a do řetězcové proměnné subvyrazy vždy zapíšeme (respektive připíšeme) shodu ve tvaru [i][j]: shoda, kde i udává o kolikátou shodu (při globálním vyhledávání) se jedná (indexováno od nuly!) a j udává, o shodu s kolikátým subvýrazem se jedná (shoda s celým regulárním výrazem je pod indexem 0).

Určitá komplikace nastává v případě, že nepoužijeme modifikátor g (globální vyhledávání). V takovém případě je vždy vyhledáváno od začátku řetězce. Podmínka while je tedy splněna vždy, pokud je v řetězci alespoň jedna shoda. Cyklus se tak stane nekonečnou smyčkou. V našem jednoduchém kódu si dovolím pro řešení použít programátorsky ne zcela nejčistší řešení, a to opuštění while cyklu pomocí break na základě otestování vlastnosti global regulárního výrazu. Zápis if(!regvyraz1­.global) break; tedy říká: Pokud regulární výraz neobsahuje modifikátor pro globální vyhledávání, opusť cyklus.

Nastíněné řešení je pouze jádrem uživatelsky komfortní aplikace. Není však již velkým problémem například místo textového vstupního pole pro regulární výraz použít rozbalovací menu s přednastavenými regulárními výrazy a podobně, a tak zpřístupnit funkčnost i uživatelům, kteří se tolik s regulárními výrazy nekamarádí.

Tento článek byl původně publikován na serveru Interval.cz, kde naleznete originální verzi článku.