20. září 2026

Alternace (NEBO) |

Alternace je v regulárních výrazech pojem, který ve skutečnosti znamená jednoduše „NEBO“.

V regulárním výrazu je označován znakem svislé čáry |.

Například potřebujeme najít názvy programovacích jazyků: HTML, PHP, Java nebo JavaScript.

Odpovídající regulární výraz: html|php|java(script)?.

Příklad použití:

let rv = /html|php|css|java(script)?/gi;

let řetězec = "Napřed se objevil HTML, pak CSS, pak JavaScript";

alert( řetězec.match(rv) ); // 'HTML', 'CSS', 'JavaScript'

Už jsme viděli něco podobného – hranaté závorky. Ty nám umožňují výběr z několika znaků, například gr[ae]y najde gray nebo grey.

Hranaté závorky umožňují jen znaky nebo znakové třídy. Alternace umožňuje libovolné výrazy. Regulární výraz A|B|C znamená jeden z výrazů A, B nebo C.

Příklad:

  • gr(a|e)y znamená přesně totéž jako gr[ae]y.
  • gra|ey znamená gra nebo ey.

Abychom aplikovali alternaci na zvolenou část vzoru, můžeme ji uzavřít do závorek:

  • Mám rád HTML|CSS znamená Mám rád HTML nebo CSS.
  • Mám rád (HTML|CSS) znamená Mám rád HTML nebo Mám rád CSS.

Příklad: regulární výraz pro čas

V předchozích článcích jsme měli úlohu na vytvoření RV pro hledání času ve tvaru hh:mm, například 12:00. Jednoduchý výraz \d\d:\d\d je však příliš neurčitý. Přijme jako čas 25:99 (protože 99 minut odpovídá vzoru, ale čas je neplatný).

Jak můžeme vytvořit lepší vzor?

Můžeme použít pečlivější porovnávání. Napřed hodiny:

  • Pokud je první číslice 0 nebo 1, pak následující číslice může být libovolná: [01]\d.
  • Jinak pokud je první číslice 2, pak následující musí být [0-3].
  • (žádná jiná první číslice není povolena)

V regulárním výrazu můžeme zapsat obě varianty pomocí alternace: [01]\d|2[0-3].

Dále minuty musejí být od 00 do 59. V jazyce regulárních výrazů to můžeme zapsat jako [0-5]\d: první číslice 0-5 a pak libovolná.

Když spojíme hodiny a minuty dohromady, získáme vzor: [01]\d|2[0-3]:[0-5]\d.

Jsme téměř hotovi, ale je tu problém. Alternace | se nyní děje mezi [01]\d a 2[0-3]:[0-5]\d.

To znamená, že minuty jsou přidány jako druhá varianta alternace, zde je to jasně vidět:

[01]\d  |  2[0-3]:[0-5]\d

Tento vzor hledá [01]\d nebo 2[0-3]:[0-5]\d.

To je však špatně, alternace by měla být použita jen v „hodinové“ části regulárního výrazu, aby umožňovala [01]\d NEBO 2[0-3]. Opravme to uzavřením „hodin“ do závorek: ([01]\d|2[0-3]):[0-5]\d.

Konečné řešení:

let rv = /([01]\d|2[0-3]):[0-5]\d/g;

alert("00:00 10:10 23:59 25:99 1:2".match(rv)); // 00:00,10:10,23:59

Úlohy

Existuje mnoho programovacích jazyků, například Java, JavaScript, PHP, C, C++.

Vytvořte regulární výraz, který je najde v řetězci Java JavaScript PHP C++ C:

let rv = /váš RV/g;

alert("Java JavaScript PHP C++ C".match(rv)); // Java JavaScript PHP C++ C

První myšlenka může být vyjmenovat jazyky a vložit mezi ně |.

To však nebude fungovat správně:

let rv = /Java|JavaScript|PHP|C|C\+\+/g;

let řetězec = "Java, JavaScript, PHP, C, C++";

alert( řetězec.match(rv) ); // Java,Java,PHP,C,C

Motor regulárních výrazů hledá alternace jednu po druhé. To znamená, že nejprve ověří, zda máme Java, pokud ne, hledá JavaScript a tak dále.

Výsledkem bude, že JavaScript nemůže být nikdy nalezen prostě proto, že Java se ověřuje jako první.

Totéž platí pro C a C++.

Tento problém má dvě řešení:

  1. Změnit pořadí, aby se delší výraz ověřoval jako první: JavaScript|Java|C\+\+|C|PHP.
  2. Sloučit varianty, které začínají stejně: Java(Script)?|C(\+\+)?|PHP.

V akci:

let rv = /Java(Script)?|C(\+\+)?|PHP/g;

let řetězec = "Java, JavaScript, PHP, C, C++";

alert( řetězec.match(rv) ); // Java,JavaScript,PHP,C,C++

„BB-značka“ vypadá jako [značka]...[/značka], kde značka je jedna z následujících: b, url nebo quote.

Například:

[b]text[/b]
[url]http://google.com[/url]

BB-značky lze vnořit do sebe. Značka však nemůže být vnořena do stejné značky, například:

Běžné:
[url] [b]http://google.com[/b] [/url]
[quote] [b]text[/b] [/quote]

Nemůže se stát:
[b][b]text[/b][/b]

Značky mohou obsahovat konce řádků, to se běžně stává:

[quote]
  [b]text[/b]
[/quote]

Vytvořte regulární výraz, který najde všechny BB-značky i s jejich obsahem.

Například:

let rv = /váš RV/příznaky;

let řetězec = "..[url]http://google.com[/url]..";
alert( řetězec.match(rv) ); // [url]http://google.com[/url]

Pokud jsou značky vnořené, potřebujeme vnější značku (pokud chceme, můžeme pokračovat v hledání v jejím obsahu):

let rv = /váš RV/příznaky;

let řetězec = "..[url][b]http://google.com[/b][/url]..";
alert( řetězec.match(rv) ); // [url][b]http://google.com[/b][/url]

Otevírací značka je \[(b|url|quote)].

Abychom pak našli vše až do uzavírací značky, použijeme vzor .*? s příznakem s, aby našel každý znak včetně nového řádku, a pak přidáme zpětný odkaz na uzavírací značku.

Celý vzor: \[(b|url|quote)\].*?\[/\1].

V akci:

let rv = /\[(b|url|quote)].*?\[\/\1]/gs;

let řetězec = `
  [b]ahoj![/b]
  [quote]
    [url]http://google.com[/url]
  [/quote]
`;

alert( řetězec.match(rv) ); // [b]ahoj![/b],[quote][url]http://google.com[/url][/quote]

Prosíme všimněte si, že jsme museli uvést únikový znak nejen před [, ale i před lomítkem uzavírací značky [\/\1], protože lomítko normálně uzavírá vzor.

Vytvořte regulární výraz, který najde řetězce ve dvojitých uvozovkách "...".

Řetězce by měly podporovat únikové znaky stejným způsobem, jako řetězce v JavaScriptu. Například uvozovky mohou být vloženy jako \", nový řádek jako \n a samotné zpětné lomítko jako \\.

let řetězec = "Tak jako \"tady\".";

Prosíme všimněte si, že uvozovky za únikovým znakem \" neukončují řetězec.

Měli bychom tedy hledat od prvních uvozovek ke druhým, ale po cestě ignorovat uvozovky za únikovým znakem.

To je klíčová součást úlohy, jinak by byla triviální.

Příklady řetězců, které se mají shodovat:

.. "otestuj mě" ..
.. "Řekni \"Ahoj\"!" ... (uvozovky s únikovým znakem uvnitř)
.. "\\" ..  (dvojité lomítko uvnitř)
.. "\\ \"" ..  (dvojité lomítko a uvozovky s únikovým znakem uvnitř)

Abychom v JavaScriptu správně předali do řetězce zpětná lomítka, musíme je zdvojit, například:

let řetězec = ' .. "otestuj mě" .. "Řekni \\"Ahoj\\"!" .. "\\\\ \\"" .. ';

// řetězec v paměti
alert(řetězec); //  .. "otestuj mě" .. "Řekni \"Ahoj\"!" .. "\\ \"" ..

Řešení: /"(\\.|[^"\\])*"/g.

Krok za krokem:

  • Nejprve najdeme otevírací uvozovky ".
  • Potom, pokud máme zpětné lomítko \\ (ve vzoru je musíme zdvojit, protože je to speciální znak), pak za ním může být jakýkoli znak (tečka).
  • V opačném případě přijmeme libovolný znak kromě uvozovek (ty znamenají konec řetězce) a zpětného lomítka (abychom zabránili osamoceným zpětným lomítkům, zpětné lomítko se používá jen s jiným symbolem za sebou): [^"\\]
  • …A tak dále až do uzavíracích uvozovek.

V akci:

let rv = /"(\\.|[^"\\])*"/g;
let řetězec = ' .. "otestuj mě" .. "Řekni \\"Ahoj\\"!" .. "\\\\ \\"" .. ';

alert( řetězec.match(rv) ); // "otestuj mě","Řekni \"Ahoj\"!","\\ \""

Napište regulární výraz, který najde značku <style...>. Měl by najít celou značku: nemusí mít žádné atributy <style> nebo jich může mít několik <style type="..." id="...">.

…Tento RV by však neměl najít <styler>!

Příklad:

let rv = /váš RV/g;

alert( '<style> <styler> <style test="...">'.match(rv) ); // <style>, <style test="...">

Začátek vzoru je zřejmý: <style.

…Pak ale nemůžeme jednoduše napsat <style.*?>, protože tomu by odpovídalo i <styler>.

Potřebujeme buď mezeru za <style a pak nepovinně něco dalšího, nebo koncové >.

V jazyce regulárních výrazů: <style(>|\s.*?>).

V akci:

let rv = /<style(>|\s.*?>)/g;

alert( '<style> <styler> <style test="...">'.match(rv) ); // <style>, <style test="...">
Mapa tutoriálu

Komentáře

přečtěte si před komentováním…
  • Máte-li návrhy na zlepšení, vytvořte prosím issue na GitHubu nebo pull request místo komentáře.
  • Pokud v článku něčemu nerozumíte, napište prosím, čemu přesně a na kterém místě.
  • Pro vložení několika slov kódu použijte značku <code>, pro několik řádků je obalte značkou <pre>, pro více než 10 řádků vložte odkaz na pískoviště (plnkr, jsbin, codepen…)