Lepkavá vlajka y, vyhledávání na pozici

Příznak y umožňuje provést vyhledávání na dané pozici ve zdrojovém řetězci.

Abychom pochopili případ použití y flag a lépe porozumět způsobům regulárních výrazů, prozkoumáme praktický příklad.

Jedním z běžných úkolů pro regulární výrazy je „lexikální analýza“:dostaneme text, např. v programovacím jazyce a je potřeba najít jeho strukturální prvky. Například HTML má značky a atributy, kód JavaScript má funkce, proměnné a tak dále.

Psaní lexikálních analyzátorů je speciální oblast s vlastními nástroji a algoritmy, takže tam nejdeme hluboko, ale máme společný úkol:něco přečíst na dané pozici.

Např. máme kódový řetězec let varName = "value" a musíme z ní přečíst název proměnné, která začíná na pozici 4 .

Název proměnné budeme hledat pomocí regulárního výrazu \w+ . Názvy proměnných JavaScriptu ve skutečnosti potřebují trochu složitější regulární výrazy pro přesnou shodu, ale tady na tom nezáleží.

  • Volání na číslo str.match(/\w+/) najde pouze první slovo v řádku (let ). To není ono.
  • Můžeme přidat příznak g . Ale pak volání str.match(/\w+/g) bude hledat všechna slova v textu, zatímco my potřebujeme jedno slovo na pozici 4 . Opět ne to, co potřebujeme.

Jak tedy hledat regulární výraz přesně na dané pozici?

Zkusme použít metodu regexp.exec(str) .

Pro regexp bez příznaků g a y , tato metoda hledá pouze první shodu, funguje přesně jako str.match(regexp) .

…Ale pokud je tam příznak g , pak provede vyhledávání v str , počínaje pozicí uloženou v regexp.lastIndex vlastnictví. A pokud najde shodu, nastaví regexp.lastIndex do indexu ihned po shodě.

Jinými slovy regexp.lastIndex slouží jako výchozí bod pro hledání, že každý regexp.exec(str) hovor se resetuje na novou hodnotu („po poslední shodě“). To je pouze v případě, že existuje g vlajka, samozřejmě.

Takže po sobě jdoucí volání na regexp.exec(str) vracet shody jednu po druhé.

Zde je příklad takových hovorů:

let str = 'let varName'; // Let's find all words in this string
let regexp = /\w+/g;

alert(regexp.lastIndex); // 0 (initially lastIndex=0)

let word1 = regexp.exec(str);
alert(word1[0]); // let (1st word)
alert(regexp.lastIndex); // 3 (position after the match)

let word2 = regexp.exec(str);
alert(word2[0]); // varName (2nd word)
alert(regexp.lastIndex); // 11 (position after the match)

let word3 = regexp.exec(str);
alert(word3); // null (no more matches)
alert(regexp.lastIndex); // 0 (resets at search end)

Můžeme dostat všechny zápasy do smyčky:

let str = 'let varName';
let regexp = /\w+/g;

let result;

while (result = regexp.exec(str)) {
  alert( `Found ${result[0]} at position ${result.index}` );
  // Found let at position 0, then
  // Found varName at position 4
}

Takové použití regexp.exec je alternativou k metodě str.matchAll , s trochu větší kontrolou nad procesem.

Vraťme se k našemu úkolu.

Můžeme ručně nastavit lastIndex na 4 , spustíte vyhledávání od dané pozice!

Takhle:

let str = 'let varName = "value"';

let regexp = /\w+/g; // without flag "g", property lastIndex is ignored

regexp.lastIndex = 4;

let word = regexp.exec(str);
alert(word); // varName

Hurá! Problém vyřešen!

Provedli jsme vyhledávání \w+ , počínaje pozicí regexp.lastIndex = 4 .

Výsledek je správný.

…Ale počkat, ne tak rychle.

Poznámka:regexp.exec hovor začne hledat na pozici lastIndex a pak jde dál. Pokud na pozici lastIndex není žádné slovo , ale je někde za ním, pak se najde:

let str = 'let varName = "value"';

let regexp = /\w+/g;

// start the search from position 3
regexp.lastIndex = 3;

let word = regexp.exec(str);
// found the match at position 4
alert(word[0]); // varName
alert(word.index); // 4

U některých úloh, včetně lexikální analýzy, je to prostě špatně. Musíme najít shodu přesně na dané pozici u textu, ne někde za ní. A to je příznak y je pro.

Příznak y dělá regexp.exec hledat přesně na pozici lastIndex , nikoli „od toho“.

Zde je stejné vyhledávání s příznakem y :

let str = 'let varName = "value"';

let regexp = /\w+/y;

regexp.lastIndex = 3;
alert( regexp.exec(str) ); // null (there's a space at position 3, not a word)

regexp.lastIndex = 4;
alert( regexp.exec(str) ); // varName (word at position 4)

Jak vidíme, regulární výraz /\w+/y neodpovídá na pozici 3 (na rozdíl od příznaku g ), ale odpovídá na pozici 4 .

Nejen, že to potřebujeme, ale při použití flagu y dochází k důležitému zvýšení výkonu .

Představte si, že máme dlouhý text a nejsou v něm vůbec žádné shody. Poté vyhledejte s příznakem g půjde až na konec textu a nic nenajde, a to zabere podstatně více času než hledání s příznakem y , která kontroluje pouze přesnou polohu.

V úlohách, jako je lexikální analýza, obvykle existuje mnoho vyhledávání na přesné pozici, abychom zjistili, co tam máme. Pomocí příznaku y je klíčem ke správné implementaci a dobrému výkonu.