Metody RegExp a String

V tomto článku se budeme zabývat různými metodami, které pracují s regulárními výrazy do hloubky.

str.match(regexp)

Metoda str.match(regexp) najde shody pro regexp v řetězci str .

Má 3 režimy:

  1. Pokud regexp nemá příznak g , pak vrátí první shodu jako pole se zachycujícími skupinami a vlastnostmi index (pozice shody), input (vstupní řetězec se rovná str ):

    let str = "I love JavaScript";
    
    let result = str.match(/Java(Script)/);
    
    alert( result[0] );     // JavaScript (full match)
    alert( result[1] );     // Script (first capturing group)
    alert( result.length ); // 2
    
    // Additional information:
    alert( result.index );  // 7 (match position)
    alert( result.input );  // I love JavaScript (source string)
  2. Pokud regexp má příznak g , pak vrátí pole všech shod jako řetězce, bez zachycení skupin a dalších podrobností.

    let str = "I love JavaScript";
    
    let result = str.match(/Java(Script)/g);
    
    alert( result[0] ); // JavaScript
    alert( result.length ); // 1
  3. Pokud neexistují žádné shody, bez ohledu na to, zda je příznak g nebo ne, null je vráceno.

    To je důležitá nuance. Pokud neexistují žádné shody, nezískáme prázdné pole, ale null . Je snadné udělat chybu a zapomenout na to, např.:

    let str = "I love JavaScript";
    
    let result = str.match(/HTML/);
    
    alert(result); // null
    alert(result.length); // Error: Cannot read property 'length' of null

    Pokud chceme, aby výsledkem bylo pole, můžeme napsat takto:

    let result = str.match(regexp) || [];

str.matchAll(regexp)

Nedávný přírůstek Toto je nedávný přírůstek do jazyka. Staré prohlížeče mohou vyžadovat polyfilly.

Metoda str.matchAll(regexp) je „novější, vylepšená“ varianta str.match .

Používá se hlavně k vyhledávání všech zápasů se všemi skupinami.

Existují 3 rozdíly oproti match :

  1. Namísto pole vrací iterovatelný objekt se shodami. Můžeme z něj vytvořit běžné pole pomocí Array.from .
  2. Každá shoda je vrácena jako pole se zachycujícími skupinami (stejný formát jako str.match bez příznaku g ).
  3. Pokud nejsou k dispozici žádné výsledky, vrátí prázdný iterovatelný objekt namísto null .

Příklad použití:

let str = '<h1>Hello, world!</h1>';
let regexp = /<(.*?)>/g;

let matchAll = str.matchAll(regexp);

alert(matchAll); // [object RegExp String Iterator], not array, but an iterable

matchAll = Array.from(matchAll); // array now

let firstMatch = matchAll[0];
alert( firstMatch[0] );  // <h1>
alert( firstMatch[1] );  // h1
alert( firstMatch.index );  // 0
alert( firstMatch.input );  // <h1>Hello, world!</h1>

Pokud použijeme for..of smyčka přes matchAll shod, pak nepotřebujeme Array.from nic víc.

str.split(regexp|substr, limit)

Rozdělí řetězec pomocí regulárního výrazu (nebo podřetězce) jako oddělovače.

Můžeme použít split s řetězci, jako je tento:

alert('12-34-56'.split('-')) // array of ['12', '34', '56']

Ale můžeme rozdělit regulárním výrazem stejným způsobem:

alert('12, 34, 56'.split(/,\s*/)) // array of ['12', '34', '56']

str.search(regexp)

Metoda str.search(regexp) vrátí pozici první shody nebo -1 pokud žádný nebyl nalezen:

let str = "A drop of ink may make a million think";

alert( str.search( /ink/i ) ); // 10 (first match position)

Důležité omezení:search najde pouze první shodu.

Pokud potřebujeme pozice dalších shod, měli bychom použít jiné prostředky, jako je najít všechny pomocí str.matchAll(regexp) .

str.replace(str|regexp, str|func)

Toto je obecná metoda pro vyhledávání a nahrazování, jedna z nejužitečnějších. Švýcarský armádní nůž pro hledání a výměnu.

Můžeme jej použít bez regulárních výrazů k vyhledání a nahrazení podřetězce:

// replace a dash by a colon
alert('12-34-56'.replace("-", ":")) // 12:34-56

Je tu však úskalí.

Při prvním argumentu replace je řetězec, pouze nahrazuje první shodu.

Můžete to vidět v příkladu výše:pouze první "-" je nahrazeno ":" .

Abychom našli všechny spojovníky, musíme použít nikoli řetězec "-" , ale regulární výraz /-/g s povinným g příznak:

// replace all dashes by a colon
alert( '12-34-56'.replace( /-/g, ":" ) )  // 12:34:56

Druhý argument je náhradní řetězec. Můžeme v něm použít speciální znaky:

Symboly Akce v náhradním řetězci
$& vloží celou shodu
$` vloží část řetězce před shodu
$' vloží část řetězce za shodu
$n if n je 1-2 místné číslo, vkládá obsah n-té skupiny zachycení, podrobnosti viz Zachytávání skupin
$<name> vloží obsah závorek s daným name , podrobnosti viz Zachycování skupin
$$ vloží znak $

Například:

let str = "John Smith";

// swap first and last name
alert(str.replace(/(john) (smith)/i, '$2, $1')) // Smith, John

V situacích, které vyžadují „chytré“ nahrazení, může být druhým argumentem funkce.

Bude volána pro každou shodu a vrácená hodnota bude vložena jako náhrada.

Funkce se volá s argumenty func(match, p1, p2, ..., pn, offset, input, groups) :

  1. match – zápas,
  2. p1, p2, ..., pn – obsah zachytávacích skupin (pokud nějaké existují),
  3. offset – postavení zápasu,
  4. input – zdrojový řetězec,
  5. groups – objekt s pojmenovanými skupinami.

Pokud v regulárním výrazu nejsou žádné závorky, pak existují pouze 3 argumenty:func(str, offset, input) .

Uveďme například všechny shody velkými písmeny:

let str = "html and css";

let result = str.replace(/html|css/gi, str => str.toUpperCase());

alert(result); // HTML and CSS

Nahraďte každou shodu její pozicí v řetězci:

alert("Ho-Ho-ho".replace(/ho/gi, (match, offset) => offset)); // 0-3-6

V příkladu níže jsou dvě závorky, takže funkce nahrazení je volána s 5 argumenty:první je úplná shoda, pak 2 závorky a za ní (v příkladu se nepoužívá) pozice shody a zdrojový řetězec:

let str = "John Smith";

let result = str.replace(/(\w+) (\w+)/, (match, name, surname) => `${surname}, ${name}`);

alert(result); // Smith, John

Pokud je skupin mnoho, je vhodné pro přístup k nim použít parametry odpočinku:

let str = "John Smith";

let result = str.replace(/(\w+) (\w+)/, (...match) => `${match[2]}, ${match[1]}`);

alert(result); // Smith, John

Nebo, pokud používáme pojmenované skupiny, pak groups objekt s nimi je vždy poslední, takže jej můžeme získat takto:

let str = "John Smith";

let result = str.replace(/(?<name>\w+) (?<surname>\w+)/, (...match) => {
  let groups = match.pop();

  return `${groups.surname}, ${groups.name}`;
});

alert(result); // Smith, John

Použití funkce nám poskytuje maximální nahrazovací sílu, protože získává všechny informace o shodě, má přístup k vnějším proměnným a může dělat všechno.

str.replaceAll(str|regexp, str|func)

Tato metoda je v podstatě stejná jako str.replace , se dvěma hlavními rozdíly:

  1. Pokud je prvním argumentem řetězec, nahradí všechny výskyty řetězce, zatímco replace nahradí pouze první výskyt .
  2. Pokud je prvním argumentem regulární výraz bez g příznak, dojde k chybě. S g flag, funguje stejně jako replace .

Hlavní případ použití pro replaceAll nahrazuje všechny výskyty řetězce.

Takhle:

// replace all dashes by a colon
alert('12-34-56'.replaceAll("-", ":")) // 12:34:56

regexp.exec(str)

regexp.exec(str) metoda vrací shodu pro regexp v řetězci str . Na rozdíl od předchozích metod se volá na regulárním výrazu, nikoli na řetězci.

Chová se odlišně v závislosti na tom, zda má regulární výraz příznak g .

Pokud neexistuje g a poté regexp.exec(str) vrátí první shodu přesně jako str.match(regexp) . Toto chování nepřináší nic nového.

Ale pokud je tam příznak g , pak:

  • Volání na číslo regexp.exec(str) vrátí první shodu a uloží pozici bezprostředně za ní do vlastnosti regexp.lastIndex .
  • Další takové volání zahájí vyhledávání od pozice regexp.lastIndex , vrátí další shodu a uloží pozici za ní do regexp.lastIndex .
  • …A tak dále.
  • Pokud neexistují žádné shody, regexp.exec vrátí null a resetuje regexp.lastIndex na 0 .

Opakovaná volání tedy vracejí všechny shody jednu po druhé pomocí vlastnosti regexp.lastIndex pro sledování aktuální pozice vyhledávání.

V minulosti před metodou str.matchAll byl přidán do JavaScriptu, volání regexp.exec byly použity ve smyčce k získání všech zápasů se skupinami:

let str = 'More about JavaScript at https://javascript.info';
let regexp = /javascript/ig;

let result;

while (result = regexp.exec(str)) {
  alert( `Found ${result[0]} at position ${result.index}` );
  // Found JavaScript at position 11, then
  // Found javascript at position 33
}

To nyní funguje také, i když pro novější prohlížeče str.matchAll je obvykle pohodlnější.

Můžeme použít regexp.exec pro vyhledávání z dané pozice ručním nastavením lastIndex .

Například:

let str = 'Hello, world!';

let regexp = /\w+/g; // without flag "g", lastIndex property is ignored
regexp.lastIndex = 5; // search from 5th position (from the comma)

alert( regexp.exec(str) ); // world

Pokud má regulární výraz příznak y , pak bude vyhledávání provedeno přesně na pozici regexp.lastIndex , dále ne.

Nahradíme příznak g s y ve výše uvedeném příkladu. Nebudou nalezeny žádné shody, protože na pozici 5 není žádné slovo :

let str = 'Hello, world!';

let regexp = /\w+/y;
regexp.lastIndex = 5; // search exactly at position 5

alert( regexp.exec(str) ); // null

To se hodí v situacích, kdy potřebujeme něco „přečíst“ z řetězce podle regulárního výrazu na přesné pozici, nikoli někde dále.

regexp.test(str)

Metoda regexp.test(str) vyhledá shodu a vrátí true/false zda existuje.

Například:

let str = "I love JavaScript";

// these two tests do the same
alert( /love/i.test(str) ); // true
alert( str.search(/love/i) != -1 ); // true

Příklad se zápornou odpovědí:

let str = "Bla-bla-bla";

alert( /love/i.test(str) ); // false
alert( str.search(/love/i) != -1 ); // false

Pokud má regulární výraz příznak g a poté regexp.test vypadá z regexp.lastIndex vlastnost a aktualizuje tuto vlastnost, stejně jako regexp.exec .

Můžeme jej tedy použít k vyhledávání z dané pozice:

let regexp = /love/gi;

let str = "I love JavaScript";

// start the search from position 10:
regexp.lastIndex = 10;
alert( regexp.test(str) ); // false (no match)
Stejný globální regulární výraz testovaný opakovaně na různých zdrojích může selhat

Pokud použijeme stejný globální regulární výraz na různé vstupy, může to vést k nesprávnému výsledku, protože regexp.test zálohy volání regexp.lastIndex vlastnost, takže hledání v jiném řetězci může začít od nenulové pozice.

Například zde nazýváme regexp.test dvakrát na stejném textu a podruhé se nezdaří:

let regexp = /javascript/g;  // (regexp just created: regexp.lastIndex=0)

alert( regexp.test("javascript") ); // true (regexp.lastIndex=10 now)
alert( regexp.test("javascript") ); // false

To je přesně proto, že regexp.lastIndex je ve druhém testu nenulový.

Abychom to vyřešili, můžeme nastavit regexp.lastIndex = 0 před každým hledáním. Nebo místo volání metod na regulárním výrazu použijte řetězcové metody str.match/search/... , nepoužívají lastIndex .


No