Někdy potřebujeme najít jen ty shody se vzorem, které se nacházejí před nebo za jiným vzorem.
K tomu existuje speciální syntaxe, nazývaná „dopředné nahlédnutí“ („lookahead“) a „zpětné nahlédnutí“ („lookbehind“). Obě společně se nazývají „nahlédnutí“ („lookaround“).
Pro začátek najděme cenu v řetězci, např. 1 krocan stojí 30€. To znamená: číslo, po němž následuje znak €.
Dopředné nahlédnutí
Syntaxe je: X(?=Y), znamená „najdi X, ale jen pokud za ním následuje Y“. Na místě X a Y může být libovolný vzor.
Pro celé číslo následované znakem € bude regulární výraz \d+(?=€):
let řetězec = "1 krocan stojí 30€";
alert( řetězec.match(/\d+(?=€)/) ); // 30, číslo 1 se ignoruje, neboť po něm nenásleduje €
Prosíme všimněte si, že nahlédnutí je pouhý test, obsah závorek (?=...) nebude do výsledku 30 zahrnut.
Když hledáme X(?=Y), motor regulárních výrazů najde X a pak ověří, zda okamžitě za ním následuje Y. Pokud ne, potenciální shoda se přeskočí a hledání pokračuje.
Jsou možné i složitější testy, např. X(?=Y)(?=Z) znamená:
- Najdi
X. - Ověř, zda
Yje okamžitě zaX(pokud ne, přeskoč ho). - Ověř, zda
Zje také okamžitě zaX(pokud ne, přeskoč ho). - Pokud oba testy prošly, je
Xshoda, jinak pokračuj v hledání.
Jinými slovy, takový vzor znamená, že hledáme X, po němž následují současně Y a Z.
To je možné jen tehdy, pokud se vzory Y a Z navzájem nevylučují.
Například \d+(?=\s)(?=.*30) hledá \d+, po němž následuje mezera (?=\s) a někde za ním je 30 (?=.*30):
let řetězec = "1 krocan stojí 30€";
alert( řetězec.match(/\d+(?=\s)(?=.*30)/) ); // 1
V našem řetězci tomu přesně odpovídá číslo 1.
Negativní dopředné hledání
Řekněme, že chceme ve stejném řetězci hledat množství, ne cenu. To znamená číslo \d+, po němž NENÁSLEDUJE €.
K tomu můžeme použít negativní dopředné hledání.
Syntaxe je: X(?!Y), znamená „najdi X, ale jen pokud za ním nenásleduje Y“.
let řetězec = "2 krocani stojí 60€";
alert( řetězec.match(/\d+\b(?!€)/g) ); // 2 (cena neodpovídá)
Zpětné hledání
Prosíme všimněte si: Zpětné hledání není podporováno v prohlížečích, které nejsou postaveny na V8, např. Safari nebo Internet Explorer.
Dopředné hledání umožňuje přidat podmínku pro to, „co následuje“.
Zpětné hledání funguje podobně, ale dívá se dozadu. To znamená, že umožňuje najít vzor jen tehdy, pokud je něco před ním.
Syntaxe je:
- Pozitivní zpětné hledání:
(?<=Y)X, najdeX, ale jen pokud před ním jeY. - Negativní zpětné hledání:
(?<!Y)X, najdeX, ale jen pokud před ním neníY.
Změňme například cenu na americké dolary. Znak dolaru se obvykle uvádí před číslem, takže pro hledání $30 použijeme (?<=\$)\d+ – číslo, před kterým je $:
let řetězec = "1 krocan stojí $30";
// znak dolaru je za únikovým znakem \$
alert( řetězec.match(/(?<=\$)\d+/) ); // 30 (samostatné číslo přeskočíme)
A pokud potřebujeme množství – číslo, před nímž není $, můžeme použít negativní zpětné hledání (?<!\$)\d+:
let řetězec = "2 krocani stojí $60";
alert( řetězec.match(/(?<!\$)\b\d+/g) ); // 2 (cena neodpovídá)
Zachytávací skupiny
Obsah uvnitř závorek obklopujících nahlédnutí se obvykle nestává součástí výsledku.
Například ve vzoru \d+(?=€) nebude znak € zachycen jako součást shody. To je přirozené: hledáme číslo \d+, zatímco (?=€) je jen test, že by po něm mělo následovat €.
V některých situacích však můžeme chtít zachytit i nahlížený výraz nebo jeho část. I to je možné. Jednoduše uzavřeme tuto část do dalších závorek.
V následujícím příkladu je znak měny (€|kr) zachycen společně s částkou:
let řetězec = "1 krocan stojí 30€";
let rv = /\d+(?=(€|kr))/; // další závorky kolem €|kr
alert( řetězec.match(rv) ); // 30, €
A zde je totéž pro zpětné nahlédnutí:
let řetězec = "1 krocan stojí $30";
let rv = /(?<=(\$|£))\d+/;
alert( řetězec.match(rv) ); // 30, $
Shrnutí
Dopředné a zpětné nahlédnutí (společně nazývaná „nahlédnutí“) jsou užitečná, když chceme najít něco, co závisí na kontextu před/za sebou.
U jednoduchých regulárních výrazů můžeme něco podobného udělat ručně. To znamená: najít všechno v jakémkoli kontextu a pak výsledky filtrovat podle kontextu v cyklu.
Nezapomeňte, že řetězec.match (bez příznaku g) a řetězec.matchAll (vždy) vrátí shody jako pole s vlastností index, takže přesně víme, kde v textu se shoda nachází, a můžeme zkontrolovat kontext.
Nahlédnutí je však obecně vhodnější.
Druhy nahlédnutí:
| Vzor | Typ | Najde |
|---|---|---|
X(?=Y) |
Pozitivní dopředné nahlédnutí | X, pokud za ním je Y |
X(?!Y) |
Negativní dopředné nahlédnutí | X, pokud za ním není Y |
(?<=Y)X |
Pozitivní zpětné nahlédnutí | X, pokud před ním je Y |
(?<!Y)X |
Negativní zpětné nahlédnutí | X, pokud před ním není Y |
Komentáře
<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…)