Preskúmajte pokročilé porovnávanie vzorov v JavaScripte pomocou regulárnych výrazov. Zoznámte sa so syntaxou regex, praktickými aplikáciami a optimalizačnými technikami pre efektívny a robustný kód.
Porovnávanie vzorov v JavaScripte pomocou regulárnych výrazov: Komplexný sprievodca
Regulárne výrazy (regex) sú mocným nástrojom na porovnávanie vzorov a manipuláciu s textom v JavaScripte. Umožňujú vývojárom vyhľadávať, validovať a transformovať reťazce na základe definovaných vzorov. Tento sprievodca poskytuje komplexný prehľad regulárnych výrazov v JavaScripte, pokrývajúc syntax, použitie a pokročilé techniky.
Čo sú regulárne výrazy?
Regulárny výraz je sekvencia znakov, ktorá definuje vzor pre vyhľadávanie. Tieto vzory sa používajú na porovnávanie a manipuláciu s reťazcami. Regulárne výrazy sú v programovaní široko používané pre úlohy ako:
- Validácia dát: Zabezpečenie, aby vstup od používateľa zodpovedal špecifickým formátom (napr. e-mailové adresy, telefónne čísla).
- Extrakcia dát: Získavanie špecifických informácií z textu (napr. extrahovanie dátumov, URL adries alebo cien).
- Vyhľadávanie a nahrádzanie: Nájdenie a nahradenie textu na základe komplexných vzorov.
- Spracovanie textu: Rozdeľovanie, spájanie alebo transformácia reťazcov na základe definovaných pravidiel.
Vytváranie regulárnych výrazov v JavaScripte
V JavaScripte je možné regulárne výrazy vytvoriť dvoma spôsobmi:
- Použitím literálu regulárneho výrazu: Vzor sa uzatvorí medzi lomky (
/). - Použitím konštruktora
RegExp: Vytvorí sa objektRegExpso vzorom ako reťazcom.
Príklad:
// Použitie literálu regulárneho výrazu
const regexLiteral = /hello/;
// Použitie konštruktora RegExp
const regexConstructor = new RegExp("hello");
Voľba medzi týmito dvoma metódami závisí od toho, či je vzor známy v čase kompilácie alebo je generovaný dynamicky. Literálny zápis použite, keď je vzor pevný a známy vopred. Konštruktor použite, keď je potrebné vzor vytvoriť programovo, najmä pri začleňovaní premenných.
Základná syntax Regex
Regulárne výrazy pozostávajú zo znakov, ktoré reprezentujú vzor, ktorý sa má porovnať. Tu sú niektoré základné komponenty regex:
- Literálne znaky: Porovnávajú sa so samotnými znakmi (napr.
/a/nájde zhodu so znakom 'a'). - Metaznaky: Majú špeciálny význam (napr.
.,^,$,*,+,?,[],{},(),\,|). - Triedy znakov: Reprezentujú sady znakov (napr.
[abc]nájde zhodu s 'a', 'b' alebo 'c'). - Kvantifikátory: Špecifikujú, koľkokrát sa má znak alebo skupina vyskytnúť (napr.
*,+,?,{n},{n,},{n,m}). - Kotvy: Porovnávajú pozície v reťazci (napr.
^porovnáva začiatok,$porovnáva koniec).
Bežné metaznaky:
.(bodka): Porovnáva akýkoľvek jeden znak okrem nového riadku.^(strieška): Porovnáva začiatok reťazca.$(dolár): Porovnáva koniec reťazca.*(hviezdička): Porovnáva nula alebo viac výskytov predchádzajúceho znaku alebo skupiny.+(plus): Porovnáva jeden alebo viac výskytov predchádzajúceho znaku alebo skupiny.?(otáznik): Porovnáva nula alebo jeden výskyt predchádzajúceho znaku alebo skupiny. Používa sa pre voliteľné znaky.[](hranaté zátvorky): Definuje triedu znakov, porovnáva akýkoľvek jeden znak v zátvorkách.{}(kučeravé zátvorky): Špecifikuje počet výskytov na porovnanie.{n}porovnáva presne n-krát,{n,}porovnáva n alebo viackrát,{n,m}porovnáva od n do m-krát.()(okrúhle zátvorky): Zoskupuje znaky a zachytáva porovnaný podreťazec.\(spätná lomka): Escapuje metaznaky, čo umožňuje ich porovnanie doslovne.|(zvislá čiara): Pôsobí ako operátor "alebo", porovnáva buď výraz pred ním, alebo za ním.
Triedy znakov:
[abc]: Porovnáva ktorýkoľvek z znakov a, b alebo c.[^abc]: Porovnáva akýkoľvek znak, ktorý *nie je* a, b alebo c.[a-z]: Porovnáva akékoľvek malé písmeno od a po z.[A-Z]: Porovnáva akékoľvek veľké písmeno od A po Z.[0-9]: Porovnáva akúkoľvek číslicu od 0 po 9.[a-zA-Z0-9]: Porovnáva akýkoľvek alfanumerický znak.\d: Porovnáva akúkoľvek číslicu (ekvivalentné[0-9]).\D: Porovnáva akýkoľvek nečíselný znak (ekvivalentné[^0-9]).\w: Porovnáva akýkoľvek znak slova (alfanumerický znak plus podčiarkovník; ekvivalentné[a-zA-Z0-9_]).\W: Porovnáva akýkoľvek znak, ktorý nie je znakom slova (ekvivalentné[^a-zA-Z0-9_]).\s: Porovnáva akýkoľvek biely znak (medzera, tabulátor, nový riadok atď.).\S: Porovnáva akýkoľvek znak, ktorý nie je bielym znakom.
Kvantifikátory:
*: Porovnáva predchádzajúci prvok nula alebo viackrát. Napríklad,a*nájde zhodu s "", "a", "aa", "aaa" atď.+: Porovnáva predchádzajúci prvok jeden alebo viackrát. Napríklad,a+nájde zhodu s "a", "aa", "aaa", ale nie s "".?: Porovnáva predchádzajúci prvok nula alebo jedenkrát. Napríklad,a?nájde zhodu s "" alebo "a".{n}: Porovnáva predchádzajúci prvok presne *n*-krát. Napríklad,a{3}nájde zhodu s "aaa".{n,}: Porovnáva predchádzajúci prvok *n* alebo viackrát. Napríklad,a{2,}nájde zhodu s "aa", "aaa", "aaaa" atď.{n,m}: Porovnáva predchádzajúci prvok od *n* do *m*-krát (vrátane). Napríklad,a{2,4}nájde zhodu s "aa", "aaa" alebo "aaaa".
Kotvy:
^: Porovnáva začiatok reťazca. Napríklad,^Hellonájde zhodu v reťazcoch, ktoré *začínajú* na "Hello".$: Porovnáva koniec reťazca. Napríklad,World$nájde zhodu v reťazcoch, ktoré *končia* na "World".\b: Porovnáva hranicu slova. Je to pozícia medzi znakom slova (\w) a znakom, ktorý nie je znakom slova (\W), alebo začiatok či koniec reťazca. Napríklad,\bword\bnájde zhodu s celým slovom "word".
Príznaky (Flags):
Príznaky regex modifikujú správanie regulárnych výrazov. Pripoja sa na koniec literálu regex alebo sa odovzdajú ako druhý argument konštruktoru RegExp.
g(global): Nájde všetky výskyty vzoru, nielen prvý.i(ignore case): Vykonáva porovnanie bez rozlišovania veľkosti písmen.m(multiline): Povolí viacriadkový režim, kde^a$porovnávajú začiatok a koniec každého riadku (oddeleného\n).s(dotAll): Umožňuje bodke (.) porovnávať aj znaky nového riadku.u(unicode): Povolí plnú podporu Unicode.y(sticky): Porovnáva iba od indexu určeného vlastnosťoulastIndexregexu.
Metódy Regex v JavaScripte
JavaScript poskytuje niekoľko metód pre prácu s regulárnymi výrazmi:
test(): Testuje, či sa reťazec zhoduje so vzorom. Vrátitruealebofalse.exec(): Vykoná vyhľadávanie zhody v reťazci. Vráti pole obsahujúce zhodujúci sa text a zachytené skupiny, alebonull, ak sa zhoda nenájde.match(): Vráti pole obsahujúce výsledky porovnania reťazca s regulárnym výrazom. Správa sa odlišne s a bez príznakug.search(): Testuje zhodu v reťazci. Vráti index prvej zhody, alebo -1, ak sa zhoda nenájde.replace(): Nahradí výskyty vzoru náhradným reťazcom alebo funkciou, ktorá vráti náhradný reťazec.split(): Rozdelí reťazec na pole podreťazcov na základe regulárneho výrazu.
Príklady použitia metód Regex:
// test()
const regex = /hello/;
const str = "hello world";
console.log(regex.test(str)); // Výstup: true
// exec()
const regex2 = /hello (\w+)/;
const str2 = "hello world";
const result = regex2.exec(str2);
console.log(result); // Výstup: ["hello world", "world", index: 0, input: "hello world", groups: undefined]
// match() s príznakom 'g'
const regex3 = /\d+/g; // Nájde jednu alebo viac číslic globálne
const str3 = "There are 123 apples and 456 oranges.";
const matches = str3.match(regex3);
console.log(matches); // Výstup: ["123", "456"]
// match() bez príznaku 'g'
const regex4 = /\d+/;
const str4 = "There are 123 apples and 456 oranges.";
const match = str4.match(regex4);
console.log(match); // Výstup: ["123", index: 11, input: "There are 123 apples and 456 oranges.", groups: undefined]
// search()
const regex5 = /world/;
const str5 = "hello world";
console.log(str5.search(regex5)); // Výstup: 6
// replace()
const regex6 = /world/;
const str6 = "hello world";
const newStr = str6.replace(regex6, "JavaScript");
console.log(newStr); // Výstup: hello JavaScript
// replace() s funkciou
const regex7 = /(\d+)-(\d+)-(\d+)/;
const str7 = "Today's date is 2023-10-27";
const newStr2 = str7.replace(regex7, (match, year, month, day) => {
return `${day}/${month}/${year}`;
});
console.log(newStr2); // Výstup: Today's date is 27/10/2023
// split()
const regex8 = /, /;
const str8 = "apple, banana, cherry";
const arr = str8.split(regex8);
console.log(arr); // Výstup: ["apple", "banana", "cherry"]
Pokročilé techniky Regex
Zachytené skupiny (Capturing Groups):
Okrúhle zátvorky () sa používajú na vytváranie zachytených skupín v regulárnych výrazoch. Zachytené skupiny umožňujú extrahovať špecifické časti zhodujúceho sa textu. Metódy exec() a match() vracajú pole, kde prvý prvok je celá zhoda a nasledujúce prvky sú zachytené skupiny.
const regex = /(\d{4})-(\d{2})-(\d{2})/;
const dateString = "2023-10-27";
const match = regex.exec(dateString);
console.log(match[0]); // Výstup: 2023-10-27 (Celá zhoda)
console.log(match[1]); // Výstup: 2023 (Prvá zachytená skupina - rok)
console.log(match[2]); // Výstup: 10 (Druhá zachytená skupina - mesiac)
console.log(match[3]); // Výstup: 27 (Tretia zachytená skupina - deň)
Pomenované zachytené skupiny (Named Capturing Groups):
ES2018 predstavil pomenované zachytené skupiny, ktoré umožňujú priradiť mená zachyteným skupinám pomocou syntaxe (?. To robí kód čitateľnejším a ľahšie udržiavateľným.
const regex = /(?\d{4})-(?\d{2})-(?\d{2})/;
const dateString = "2023-10-27";
const match = regex.exec(dateString);
console.log(match.groups.year); // Výstup: 2023
console.log(match.groups.month); // Výstup: 10
console.log(match.groups.day); // Výstup: 27
Nezachytené skupiny (Non-Capturing Groups):
Ak potrebujete zoskupiť časti regexu bez ich zachytenia (napr. pre aplikovanie kvantifikátora na skupinu), môžete použiť nezachytenú skupinu so syntaxou (?:...). Tým sa zabráni zbytočnému alokovaniu pamäte pre zachytené skupiny.
const regex = /(?:https?:\/\/)?([\w\.]+)/; // Nájde zhodu s URL, ale zachytí iba názov domény
const url = "https://www.example.com/path";
const match = regex.exec(url);
console.log(match[1]); // Výstup: www.example.com
Lookarounds (Pohľady):
Lookarounds sú tvrdenia s nulovou šírkou, ktoré nachádzajú zhodu na pozícii v reťazci na základe vzoru, ktorý predchádza (lookbehind) alebo nasleduje (lookahead) túto pozíciu, bez toho, aby bol vzor lookaroundu zahrnutý do samotnej zhody.
- Pozitívny lookahead:
(?=...)Nájde zhodu, ak vzor vnútri lookaheadu *nasleduje* za aktuálnou pozíciou. - Negatívny lookahead:
(?!...)Nájde zhodu, ak vzor vnútri lookaheadu *nenasleduje* za aktuálnou pozíciou. - Pozitívny lookbehind:
(?<=...)Nájde zhodu, ak vzor vnútri lookbehindu *predchádza* aktuálnej pozícii. - Negatívny lookbehind:
(? Nájde zhodu, ak vzor vnútri lookbehindu *nepredchádza* aktuálnej pozícii.
Príklad:
// Pozitívny lookahead: Získaj cenu, iba ak za ňou nasleduje USD
const regex = /\d+(?= USD)/;
const text = "The price is 100 USD";
const match = text.match(regex);
console.log(match); // Výstup: ["100"]
// Negatívny lookahead: Získaj slovo, iba ak za ním nenasleduje číslo
const regex2 = /\b\w+\b(?! \d)/;
const text2 = "apple 123 banana orange 456";
const matches = text2.match(regex2);
console.log(matches); // Výstup: null, pretože match() vráti iba prvú zhodu bez príznaku 'g', čo nie je to, čo potrebujeme.
// oprava:
const regex3 = /\b\w+\b(?! \d)/g;
const text3 = "apple 123 banana orange 456";
const matches3 = text3.match(regex3);
console.log(matches3); // Výstup: [ 'banana' ]
// Pozitívny lookbehind: Získaj hodnotu, iba ak jej predchádza $
const regex4 = /(?<=\$)\d+/;
const text4 = "The price is $200";
const match4 = text4.match(regex4);
console.log(match4); // Výstup: ["200"]
// Negatívny lookbehind: Získaj slovo, iba ak mu nepredchádza slovo 'not'
const regex5 = /(?
Spätné referencie (Backreferences):
Spätné referencie umožňujú odkazovať na predtým zachytené skupiny v rámci toho istého regulárneho výrazu. Používajú syntax \1, \2 atď., kde číslo zodpovedá číslu zachytenej skupiny.
const regex = /([a-z]+) \1/;
const text = "hello hello world";
const match = regex.exec(text);
console.log(match); // Výstup: ["hello hello", "hello", index: 0, input: "hello hello world", groups: undefined]
Praktické aplikácie regulárnych výrazov
Validácia e-mailových adries:
Bežným prípadom použitia regulárnych výrazov je validácia e-mailových adries. Hoci dokonalý regex na validáciu e-mailov je extrémne komplexný, tu je zjednodušený príklad:
const emailRegex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
console.log(emailRegex.test("test@example.com")); // Výstup: true
console.log(emailRegex.test("invalid-email")); // Výstup: false
console.log(emailRegex.test("test@sub.example.co.uk")); // Výstup: true
Extrakcia URL adries z textu:
Môžete použiť regulárne výrazy na extrakciu URL adries z bloku textu:
const urlRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;
const text = "Visit our website at https://www.example.com or check out http://blog.example.org.";
const urls = text.match(urlRegex);
console.log(urls); // Výstup: ["https://www.example.com", "http://blog.example.org"]
Spracovanie CSV dát:
Regulárne výrazy môžu byť použité na spracovanie dát vo formáte CSV (Comma-Separated Values). Tu je príklad rozdelenia reťazca CSV na pole hodnôt, pričom sa správne spracúvajú polia v úvodzovkách:
const csvString = 'John,Doe,"123, Main St",New York';
const csvRegex = /(?:"([^"]*(?:""[^"]*)*)")|([^,]+)/g; //Opravený CSV regex
let values = [];
let match;
while (match = csvRegex.exec(csvString)) {
values.push(match[1] ? match[1].replace(/""/g, '"') : match[2]);
}
console.log(values); // Výstup: ["John", "Doe", "123, Main St", "New York"]
Validácia medzinárodných telefónnych čísel
Validácia medzinárodných telefónnych čísel je zložitá kvôli rôznym formátom a dĺžkam. Robustné riešenie často zahŕňa použitie knižnice, ale zjednodušený regex môže poskytnúť základnú validáciu:
const phoneRegex = /^\+(?:[0-9] ?){6,14}[0-9]$/;
console.log(phoneRegex.test("+1 555 123 4567")); // Výstup: true (Príklad US)
console.log(phoneRegex.test("+44 20 7946 0500")); // Výstup: true (Príklad UK)
console.log(phoneRegex.test("+81 3 3224 5000")); // Výstup: true (Príklad Japonsko)
console.log(phoneRegex.test("123-456-7890")); // Výstup: false
Validácia sily hesla
Regulárne výrazy sú užitočné pre vynucovanie politík sily hesla. Nižšie uvedený príklad kontroluje minimálnu dĺžku, veľké písmeno, malé písmeno a číslo.
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/;
console.log(passwordRegex.test("P@ssword123")); // Výstup: true
console.log(passwordRegex.test("password")); // Výstup: false (žiadne veľké písmeno ani číslo)
console.log(passwordRegex.test("Password")); // Výstup: false (žiadne číslo)
console.log(passwordRegex.test("Pass123")); // Výstup: false (žiadne malé písmeno)
console.log(passwordRegex.test("P@ss1")); // Výstup: false (menej ako 8 znakov)
Techniky optimalizácie Regex
Regulárne výrazy môžu byť výpočtovo náročné, najmä pri zložitých vzoroch alebo veľkých vstupoch. Tu sú niektoré techniky na optimalizáciu výkonu regex:
- Buďte špecifickí: Vyhnite sa používaniu príliš všeobecných vzorov, ktoré môžu nájsť viac zhôd, ako bolo zamýšľané.
- Používajte kotvy: Kedykoľvek je to možné, ukotvite regex na začiatok alebo koniec reťazca (
^,$). - Vyhnite sa spätnému sledovaniu (Backtracking): Minimalizujte spätné sledovanie použitím posesívnych kvantifikátorov (napr.
++namiesto+) alebo atómových skupín ((?>...)), ak je to vhodné. - Kompilujte raz: Ak používate ten istý regex viackrát, skompilujte ho raz a opakovane použite objekt
RegExp. - Používajte triedy znakov rozumne: Triedy znakov (
[]) sú vo všeobecnosti rýchlejšie ako alternácie (|). - Udržujte to jednoduché: Vyhnite sa príliš zložitým regexom, ktoré sú ťažko pochopiteľné a udržiavateľné. Niekedy môže byť efektívnejšie rozdeliť zložitú úlohu na viacero jednoduchších regexov alebo použiť iné techniky manipulácie s reťazcami.
Bežné chyby pri používaní Regex
- Zabudnutie na escapovanie metaznakov: Neescapovanie špeciálnych znakov ako
.,*,+,?,$,^,(,),[,],{,},|a\, keď ich chcete porovnať doslovne. - Nadmerné používanie
.(bodky): Bodka porovnáva akýkoľvek znak (okrem nového riadku v niektorých režimoch), čo môže viesť k neočakávaným zhodám, ak sa nepoužíva opatrne. Buďte špecifickejší, keď je to možné, pomocou tried znakov alebo iných reštriktívnejších vzorov. - Chamtivosť (Greediness): Štandardne sú kvantifikátory ako
*a+chamtivé a nájdu čo najdlhšiu možnú zhodu. Použite lenivé kvantifikátory (*?,+?), keď potrebujete nájsť čo najkratšiu možnú zhodu. - Nesprávne použitie kotiev: Nepochopenie správania
^(začiatok reťazca/riadku) a$(koniec reťazca/riadku) môže viesť k nesprávnym zhodám. Nezabudnite použiť príznakm(multiline) pri práci s viacriadkovými reťazcami, ak chcete, aby^a$porovnávali začiatok a koniec každého riadku. - Neriešenie okrajových prípadov: Nezohľadnenie všetkých možných vstupných scenárov a okrajových prípadov môže viesť k chybám. Dôkladne testujte svoje regexy s rôznymi vstupmi, vrátane prázdnych reťazcov, neplatných znakov a hraničných podmienok.
- Problémy s výkonom: Vytváranie príliš zložitých a neefektívnych regexov môže spôsobiť problémy s výkonom, najmä pri veľkých vstupoch. Optimalizujte svoje regexy použitím špecifickejších vzorov, vyhýbaním sa zbytočnému spätnému sledovaniu a kompilovaním regexov, ktoré sa používajú opakovane.
- Ignorovanie kódovania znakov: Nesprávne zaobchádzanie s kódovaním znakov (najmä Unicode) môže viesť k neočakávaným výsledkom. Použite príznak
upri práci so znakmi Unicode, aby ste zabezpečili správne porovnávanie.
Záver
Regulárne výrazy sú cenným nástrojom na porovnávanie vzorov a manipuláciu s textom v JavaScripte. Zvládnutie syntaxe a techník regex vám umožní efektívne riešiť širokú škálu problémov, od validácie dát po komplexné spracovanie textu. Porozumením konceptov diskutovaných v tomto sprievodcovi a praxou na reálnych príkladoch sa môžete stať zdatnými v používaní regulárnych výrazov a vylepšiť svoje zručnosti vo vývoji v JavaScripte.
Pamätajte, že regulárne výrazy môžu byť zložité a často je užitočné ich dôkladne testovať pomocou online testerov regex, ako sú regex101.com alebo regexr.com. To vám umožní vizualizovať zhody a efektívne odladiť akékoľvek problémy. Šťastné kódovanie!