JavaScript pro začátečníky: Učení regulárních výrazů. Expresivní JavaScript: regulární výrazy

Regulární výrazy

Regulární výraz je objekt, který popisuje znakový vzor. Třída RegExp v JavaScriptu představuje regulární výrazy a objekty tříd String a RegExp definují metody, které používají regulární výrazy k provádění porovnávání vzorů a vyhledávání a nahrazování textu. Gramatika regulárních výrazů JavaScriptu obsahuje poměrně kompletní podmnožinu syntaxe regulárních výrazů používané v Perlu 5, takže pokud máte zkušenosti s Perlem, můžete snadno psát vzory v programech JavaScript.

Funkce regulárních výrazů Perlu, které nejsou podporovány v ECMAScriptu, zahrnují příznaky s (jednořádkový režim) a x (rozšířená syntaxe); escape sekvence \a, \e, \l, \u, \L, \U, \E, \Q, \A, \Z, \z a \G a další rozšířené konstrukce začínající na (?.

Definování regulárních výrazů

V JavaScriptu jsou regulární výrazy reprezentovány objekty RegExp. Objekty RegExp lze vytvořit pomocí konstruktoru RegExp(), ale častěji jsou vytvořeny pomocí speciální doslovné syntaxe. Stejně jako jsou řetězcové literály zadány jako znaky ohraničené uvozovkami, literály regulárních výrazů jsou určeny jako znaky ohraničené dvojicí lomítek (/). Váš kód JavaScript tedy může obsahovat řádky jako je tento:

Vzor var = /s$/;

Tento řádek vytvoří nový objekt RegExp a přiřadí jej k proměnné vzor. Tento objekt RegExp hledá všechny řetězce končící znakem "s". Stejný regulární výraz lze definovat pomocí konstruktoru RegExp():

Vzor var = new RegExp("s$");

Specifikace vzoru regulárního výrazu se skládá ze sekvence znaků. Většina znaků, včetně všech alfanumerických, doslova popisuje znaky, které musí být přítomny. To znamená, že regulární výraz /java/ odpovídá všem řádkům obsahujícím podřetězec „java“.

Jiné znaky v regulárních výrazech nejsou určeny k nalezení jejich přesných ekvivalentů, ale mají spíše speciální význam. Například regulární výraz /s$/ obsahuje dva znaky. První znak s označuje hledání doslovného znaku. Za druhé, $ je speciální metaznak, který označuje konec řádku. Tento regulární výraz tedy odpovídá libovolnému řetězci končícímu znakem s.

Následující části popisují různé znaky a metaznaky používané v regulárních výrazech v JavaScriptu.

Doslovné postavy

Jak bylo uvedeno dříve, všechny abecední znaky a čísla v regulárních výrazech se shodují. Syntaxe regulárních výrazů v JavaScriptu také podporuje možnost specifikovat určité neabecední znaky pomocí escape sekvencí začínajících znakem zpětného lomítka (\). Například sekvence \n odpovídá znaku nového řádku. Tyto symboly jsou uvedeny v tabulce níže:

Některá interpunkční znaménka mají v regulárních výrazech zvláštní význam:

^ $ . * + ? = ! : | \ / () { } -

Význam těchto symbolů je vysvětlen v následujících částech. Některé z nich mají zvláštní význam pouze v určitých kontextech regulárních výrazů, zatímco v jiných kontextech jsou interpretovány doslovně. Obecně však platí, že chcete-li doslovně zahrnout některý z těchto znaků do regulárního výrazu, musíte mu předcházet znak zpětného lomítka. Ostatní znaky, jako jsou uvozovky a @, nemají žádný zvláštní význam a jednoduše se shodují v regulárních výrazech.

Pokud si přesně nepamatujete, kterým znakům by mělo předcházet \, můžete před kterýkoli ze znaků bezpečně vložit zpětné lomítko. Mějte však na paměti, že mnoho písmen a číslic nabývá zvláštních významů, když je zkombinujete se znakem lomítka, takže písmena a čísla, která doslova hledáte, by neměly předcházet znak \. Chcete-li do regulárního výrazu zahrnout samotný znak zpětného lomítka, musíte mu samozřejmě předcházet další znak zpětného lomítka. Například následující regulární výraz odpovídá libovolnému řetězci, který obsahuje znak zpětného lomítka: /\\/.

Třídy postav

Jednotlivé doslovné znaky lze spojovat do tříd znaků tak, že je uzavřete do hranatých závorek. Třída znaků odpovídá libovolnému znaku obsaženému v této třídě. Regulární výraz // tedy odpovídá jednomu ze znaků a, b nebo c.

Třídy záporných znaků lze také definovat tak, aby odpovídaly jakémukoli znaku kromě těch, které jsou uvedeny v závorkách. Třída znaků negace je určena znakem ^ jako prvním znakem za levou závorkou. Regulární výraz /[^abc]/ odpovídá libovolnému znaku kromě a, b nebo c. Ve znakových třídách lze rozsah znaků zadat pomocí pomlčky. Všechna malá písmena latinky lze nalézt pomocí výrazu // a jakékoli písmeno nebo číslo ze znakové sady latinky lze nalézt pomocí výrazu //.

Některé třídy znaků jsou obzvláště běžné, takže syntaxe regulárních výrazů v JavaScriptu obsahuje speciální znaky a sekvence escape, které je reprezentují. \s tedy odpovídá mezerě, tabulátoru a jakýmkoli bílým znakům Unicode a \S odpovídá všem znakům mezer v Unicode.

Níže uvedená tabulka obsahuje seznam těchto speciálních znaků a syntaxi tříd znaků. (Upozorňujeme, že některé sekvence escape třídy znaků odpovídají pouze znakům ASCII a nejsou rozšířeny tak, aby fungovaly se znaky Unicode. Můžete explicitně definovat své vlastní třídy znaků Unicode, například /[\u0400-\u04FF]/ odpovídá libovolnému znaku azbuky .)

Třídy znaků s regulárním výrazem v JavaScriptu
Symbol Korespondence
[...] Kterýkoli ze znaků uvedených v závorkách
[^...] Kterýkoli ze znaků neuvedených v závorkách
. Jakýkoli znak jiný než nový řádek nebo jiný oddělovač řádků Unicode
\w Libovolný textový znak ASCII. Ekvivalent
\W Jakýkoli znak, který není textovým znakem ASCII. Ekvivalentní [^a-zA-Z0-9_]
\s Libovolný znak mezery ze sady Unicode
\S Libovolný znak bez mezer ze sady Unicode. Upozorňujeme, že znaky \w a \S nejsou totéž
\d Jakákoli čísla ASCII. Ekvivalent
\D Jakýkoli znak jiný než čísla ASCII. Odpovídá [^0-9]
[\b] Doslovný znak backspace

Všimněte si, že sekvence speciálních znaků třídy mohou být uzavřeny do hranatých závorek. \s odpovídá libovolnému znaku mezery a \d libovolné číslici, proto /[\s\d]/ odpovídá libovolnému znaku mezery nebo číslici.

Opakování

Vzhledem k dosud získaným znalostem syntaxe regulárních výrazů můžeme dvoumístné číslo popsat jako /\d\d/ nebo čtyřmístné jako /\d\d\d\d/, ale neumíme např. , popisují číslo skládající se z libovolného počtu číslic nebo řetězce tří písmen, za nimiž následuje volitelná číslice. Tyto složitější vzory používají syntaxi regulárního výrazu, která určuje, kolikrát lze daný prvek regulárního výrazu opakovat.

Opakované symboly vždy sledují vzor, ​​na který jsou aplikovány. Některé typy opakování se používají poměrně často a pro označení těchto případů jsou k dispozici speciální symboly. Například + odpovídá jedné nebo více instancím předchozího vzoru. Následující tabulka obsahuje souhrn syntaxe opakování:

Na následujících řádcích je uvedeno několik příkladů:

Vzor var = /\d(2,4)/; // Odpovídá číslu obsahujícímu dvě až čtyři číslice vzor = /\w(3)\d?/; // Shodujte přesně tři znaky slova a jeden volitelný vzor číslic = /\s+java\s+/; // Odpovídá slovu "java" s jednou nebo více mezerami // před a za ním pattern = /[^(]*/; // Odpovídá nule nebo více znakům jiným než úvodní závorka

Buďte opatrní při používání opakujících se znaků * a ?. Mohou odpovídat absenci vzoru specifikovaného před nimi, a tedy absenci znaků. Například regulární výraz /a*/ odpovídá řetězci „bbbb“, protože neobsahuje znak a.

Znaky opakování uvedené v tabulce představují maximální možný počet opakování, který umožní shodu následujících částí regulárního výrazu. Říkáme, že toto je chamtivé opakování. Je také možné realizovat opakování prováděné nezištným způsobem. Za opakovací symbol (nebo symboly) stačí uvést otazník: ??, +?, *? nebo dokonce (1,5)?.

Například regulární výraz /a+/ odpovídá jednomu nebo více výskytům písmene a. Aplikováno na řetězec "aaa" odpovídá všem třem písmenům. Na druhou stranu výraz /a+?/ odpovídá jedné nebo více instancím písmene a a vybere nejmenší možný počet znaků. Při použití na stejný řetězec se tento vzor shoduje pouze s prvním písmenem a.

„Nenasytné“ opakování ne vždy přináší očekávaný výsledek. Zvažte vzor /a+b/, který odpovídá jednomu nebo více a následovaným b. Při aplikaci na řetězec "aaab" odpovídá celému řetězci.

Nyní se podíváme na "nechamtivou" verzi /a+?b/. Někdo by si mohl myslet, že se bude shodovat s ab, kterému předchází pouze jedno a. Pokud se použije na stejný řetězec, očekává se, že „aaab“ bude odpovídat jedinému znaku a a poslednímu znaku b. Tento vzor však ve skutečnosti odpovídá celému řetězci, stejně jako lakomá verze. Faktem je, že vyhledávání vzoru regulárního výrazu se provádí nalezením první pozice v řetězci, od které je možná shoda. Vzhledem k tomu, že shoda je možná počínaje prvním znakem řetězce, kratší shody začínající od následujících znaků se ani neberou v úvahu.

Alternativy, seskupování a odkazy

Gramatika regulárních výrazů obsahuje speciální znaky pro definování alternativ, seskupování podvýrazů a odkazy na předchozí podvýrazy. Symbol potrubí | slouží k oddělení alternativ. Například /ab|cd|ef/ odpovídá buď řetězci "ab", nebo řetězci "cd", nebo řetězci "ef" a vzor /\d(3)|(4)/ odpovídá buď třem číslicím nebo čtyři malá písmena.

Všimněte si, že alternativy jsou zpracovávány zleva doprava, dokud není nalezena shoda. Pokud je nalezena shoda s levou alternativou, pravá je ignorována, i když lze dosáhnout „lepší“ shody. Proto, když je vzor /a|ab/ aplikován na řetězec "ab", bude odpovídat pouze prvnímu znaku.

Závorky mají v regulárních výrazech více významů. Jedním z nich je seskupování jednotlivých prvků do jednoho podvýrazu tak, aby prvky při použití speciálních znaků |, *, +, ? a ostatní jsou považovány za jeden celek. Vzor /java(script)?/ se například shoduje se slovem „java“ následovaným nepovinným slovem „script“ a /(ab|cd)+|ef)/ odpovídá buď řetězci „ef“ nebo jednomu či více opakování jednoho ze řetězců "ab" nebo "cd".

Dalším použitím závorek v regulárních výrazech je definování dílčích vzorů v rámci vzoru. Když je v cílovém řetězci nalezena shoda regulárního výrazu, lze extrahovat část cílového řetězce, která odpovídá jakémukoli konkrétnímu dílčímu vzoru uzavřenému v závorkách.

Předpokládejme, že chcete najít jedno nebo více malých písmen následovaných jedním nebo více čísly. K tomu můžete použít šablonu /+\d+/. Ale předpokládejme také, že chceme pouze čísla na konci každého zápasu. Pokud dáme tuto část vzoru do závorek (/+(\d+)/), můžeme extrahovat čísla ze všech nalezených shod. Jak se to dělá, bude popsáno níže.

Související použití závorkových podvýrazů je odkazovat na podvýrazy z předchozí části stejného regulárního výrazu. Toho je dosaženo zadáním jedné nebo více číslic za znakem \. Čísla označují pozici podvýrazu v závorkách v rámci regulárního výrazu. Například \1 odkazuje na první podvýraz a \3 odkazuje na třetí. Všimněte si, že podvýrazy lze vnořovat do sebe, takže při počítání se používá pozice levé závorky. Například v následujícím regulárním výrazu bude vnořený odkaz na podvýraz (kript) vypadat takto \2:

/(ava(kript)?)\sis\s(zábava\w*)/

Odkaz na předchozí podvýraz neukazuje na vzor tohoto podvýrazu, ale na nalezený text, který tomuto vzoru odpovídá. Proto lze odkazy použít k zavedení omezení, které vybere části řetězce, které obsahují přesně stejné znaky. Například následující regulární výraz odpovídá žádnému nebo více znakům uvnitř jednoduchých nebo dvojitých uvozovek. Nevyžaduje však, aby se úvodní a závěrečné uvozovky vzájemně shodovaly (to znamená, že obě uvozovky jsou jednoduché nebo dvojité):

/[""][^""]*[""]/

Můžeme požadovat, aby se uvozovky shodovaly pomocí odkazu, jako je tento:

Zde \1 odpovídá prvnímu podvýrazu. V tomto příkladu odkaz zavádí omezení, které vyžaduje, aby koncová uvozovka odpovídala úvodní uvozovce. Tento regulární výraz neumožňuje jednoduché uvozovky uvnitř dvojitých uvozovek a naopak.

Je také možné seskupit prvky v regulárním výrazu, aniž byste na tyto prvky vytvořili číslovaný odkaz. Místo jednoduchého seskupování prvků mezi ( a ), začněte skupinu symboly (?: a ukončete ji symbolem). Zvažte například následující vzorec:

/(ava(?:cript)?)\sis\s(zábava\w*)/

Zde je podvýraz (?:cript) potřebný pouze pro seskupení, aby bylo možné na skupinu použít opakovací znak ? Tyto upravené závorky nevytvářejí odkaz, takže v tomto regulárním výrazu \2 odkazuje na text, který odpovídá vzoru (zábava\w*).

Následující tabulka uvádí výběrové, seskupovací a referenční operátory v regulárních výrazech:

Výběr, seskupování a propojení symbolů regulárních výrazů v JavaScriptu
Symbol Význam
| Alternativní. Odpovídá buď podvýrazu vlevo, nebo podvýrazu vpravo.
(...) Seskupování. Seskupuje prvky do jedné jednotky, kterou lze použít se znaky *, +, ?, | atd. Také si pamatuje znaky odpovídající této skupině pro použití v následujících odkazech.
(?:...) Pouze seskupení. Seskupuje prvky do jedné jednotky, ale nepamatuje si znaky odpovídající této skupině.
\číslo Shoduje se se stejnými znaky, které byly nalezeny při porovnávání čísla skupiny. Skupiny jsou podvýrazy uvnitř (případně vnořených) závorek. Čísla skupin se přidělují počítáním levých závorek zleva doprava. Skupiny vytvořené pomocí symbolů (?:) se nečíslují.

Určení shodné pozice

Jak bylo popsáno dříve, mnoho prvků regulárního výrazu odpovídá jedinému znaku v řetězci. Například \s odpovídá jednomu prázdnému znaku. Jiné prvky regulárního výrazu odpovídají pozicím mezi znaky spíše než samotným znakům. Například \b odpovídá hranici slova – hranici mezi \w (textový znak ASCII) a \W (netextový znak) nebo hranici mezi textovým znakem ASCII a začátkem nebo koncem řádku.

Prvky jako \b neurčují žádné znaky, které musí být přítomny ve shodném řetězci, ale určují platné pozice pro shodu. Tyto prvky se někdy nazývají kotevní prvky regulárního výrazu, protože ukotvují vzor na konkrétní pozici v řetězci. Nejčastěji používané kotevní prvky jsou ^ a $, které spojují vzory se začátkem a koncem řádku.

Například slovo "JavaScript" na vlastním řádku lze najít pomocí regulárního výrazu /^JavaScript$/. Chcete-li najít jediné slovo "Java" (spíše než předponu jako "JavaScript"), můžete zkusit použít vzor /\sJava\s/, který vyžaduje mezeru před a za slovem.

Takové řešení však vyvolává dva problémy. Za prvé, najde slovo „Java“ pouze tehdy, je-li obklopeno mezerami na obou stranách, a nebude jej moci najít na začátku nebo na konci řádku. Za druhé, když se tento vzor shoduje, řetězec, který vrací, bude obsahovat úvodní a koncové mezery, což není přesně to, co chceme. Takže namísto použití vzoru, který odpovídá mezerám \s, použijeme vzor (nebo kotvu), který odpovídá hranicím slov \b. Výsledkem bude následující výraz: /\bJava\b/.

Kotevní prvek \B odpovídá pozici, která není hranicí slova. To znamená, že vzor /\Bcript/ bude odpovídat slovům „JavaScript“ a „postscript“ a nebude odpovídat slovům „script“ nebo „Scripting“.

Libovolné regulární výrazy mohou také sloužit jako kotevní podmínky. Pokud mezi znaky (?= a) vložíte výraz, stane se to dopředným testem shody proti následným znakům, který vyžaduje, aby tyto znaky odpovídaly zadanému vzoru, ale nebyly zahrnuty do vyhledávacího řetězce.

Chcete-li například odpovídat názvu běžného programovacího jazyka, za kterým následuje dvojtečka, můžete použít výraz /ava(cript)?(?=\:)/. Tento vzor odpovídá slovu „JavaScript“ v řetězci „JavaScript: The Definitive Guide“, ale nebude odpovídat slovu „Java“ v řetězci „Java v kostce“, protože za ním nenásleduje dvojtečka.

Pokud zadáte podmínku (?!), bude se jednat o negativní dopřednou kontrolu následujících znaků, která vyžaduje, aby následující znaky neodpovídaly zadanému vzoru, například vzor /Java(?!Script)(\w*. )/ odpovídá podřetězci „Java“, za kterým následuje velké písmeno a libovolný počet textových znaků ASCII, za předpokladu, že za podřetězcem „Java“ nenásleduje podřetězec „Skript“ bude odpovídat řetězci „JavaBeans“. neodpovídá řetězci "Javanese", bude odpovídat řetězci "JavaScrip", ale nebude odpovídat řetězcům "JavaScript" nebo "JavaScripter".

Níže uvedená tabulka obsahuje seznam kotevních znaků regulárních výrazů:

Kotevní znaky regulárních výrazů
Symbol Význam
^ Odpovídá začátku řetězcového výrazu nebo začátku řádku při víceřádkovém vyhledávání.
$ Odpovídá konci řetězcového výrazu nebo konci řádku ve víceřádkovém vyhledávání.
\b Odpovídá hranici slova, tzn. odpovídá pozici mezi znakem \w a znakem \W nebo mezi znakem \w a začátkem nebo koncem řádku. (Všimněte si však, že [\b] odpovídá znaku backspace.)
\B Odpovídá pozici, která není hranicí slova.
(?=p) Pozitivní dopředná kontrola pro následující znaky. Vyžaduje následující znaky, aby odpovídaly vzoru p, ale nezahrnuje tyto znaky do shodného řetězce.
(?!p) Negativní dopředná kontrola pro následující znaky. Vyžaduje, aby následující znaky neodpovídaly vzoru p.

Vlajky

A jeden poslední prvek gramatiky regulárních výrazů. Příznaky regulárních výrazů určují pravidla pro porovnávání vzorů na vysoké úrovni. Na rozdíl od zbytku gramatiky regulárních výrazů nejsou příznaky specifikovány mezi znaky lomítka, ale za druhým. JavaScript podporuje tři příznaky.

Vlajka i určuje, že shoda vzorů by neměla rozlišovat malá a velká písmena a vlajka g- že vyhledávání má být globální, tzn. musí být nalezeny všechny shody v řetězci. Vlajka m provádí vyhledávání vzoru ve víceřádkovém režimu. Pokud hledaný řetězcový výraz obsahuje nové řádky, pak v tomto režimu kotevní znaky ^ a $, kromě toho, že odpovídají začátku a konci celého řetězcového výrazu, odpovídají také začátku a konci každého textového řádku. Například vzor /java$/im odpovídá jak „java“, tak „Java\nis fun“.

Tyto vlajky lze kombinovat v libovolné kombinaci. Chcete-li například vyhledat první výskyt slova „java“ (nebo „Java“, „JAVA“ atd.) bez ohledu na velikost písmen, můžete použít regulární výraz bez rozlišení velkých a malých písmen /\bjava\b/ i. A abyste našli všechny výskyty tohoto slova v řetězci, můžete přidat příznak g: /\bjava\b/gi.

Metody třídy String pro vyhledávání podle vzoru

Až do tohoto bodu jsme diskutovali o gramatice generovaných regulárních výrazů, ale nezkoumali jsme, jak lze tyto regulární výrazy ve skutečnosti použít ve skriptech JavaScript. V této části probereme metody objektu String, které používají regulární výrazy pro porovnávání vzorů a hledání s náhradou. A pak budeme pokračovat v rozhovoru o porovnávání vzorů s regulárními výrazy tím, že se podíváme na objekt RegExp a jeho metody a vlastnosti.

Řetězce podporují čtyři metody využívající regulární výrazy. Nejjednodušší z nich je metoda vyhledávání(). Vezme regulární výraz jako argument a vrátí buď pozici prvního znaku shodného podřetězce, nebo -1, pokud není nalezena žádná shoda. Například následující volání vrátí 4:

Var vysledek = "JavaScript".search(/script/i); // 4

Pokud argument metody search() není regulární výraz, je nejprve převeden předáním konstruktoru RegExp. Metoda search() nepodporuje globální vyhledávání a ignoruje příznak g ve svém argumentu.

Metoda nahradit() provede operaci hledání a nahrazení. Jako první argument bere regulární výraz a jako druhý náhradní řetězec. Metoda hledá na řádku, na kterém je volána, shodu se zadaným vzorem.

Pokud regulární výraz obsahuje příznak g, metoda replace() nahradí všechny nalezené shody náhradním řetězcem. V opačném případě nahradí pouze první nalezenou shodu. Pokud je prvním argumentem metody replace() spíše řetězec než regulární výraz, pak metoda provede doslovné hledání řetězce namísto jeho převodu na regulární výraz pomocí konstruktoru RegExp() jako metoda search().

Jako příklad můžeme použít metodu replace() ke konzistentnímu psaní velkých písmen slova „JavaScript“ na celém řádku textu:

// Bez ohledu na velikost písmen, nahradíme je slovem v požadovaném případě var result = "javascript".replace(/JavaScript/ig, "JavaScript");

Metoda replace() je výkonnější, než by naznačoval tento příklad. Dovolte mi připomenout, že podvýrazy v závorkách v rámci regulárního výrazu jsou číslovány zleva doprava a že regulární výraz si pamatuje text odpovídající každému z podvýrazů. Pokud náhradní řetězec obsahuje znak $ následovaný číslem, metoda nahradit() nahradí tyto dva znaky textem, který odpovídá zadanému podvýrazu. To je velmi užitečná funkce. Můžeme jej použít například k nahrazení rovných uvozovek v řetězci typografickými uvozovkami, které jsou simulovány ASCII znaky:

// Citace je uvozovka, za kterou následuje libovolný počet znaků // kromě uvozovek (které si pamatujeme), po níž následuje další uvozovka // var quote = /"([^"]*)"/g; // Nahraďte rovné uvozovky s typografickými a ponechat "$1" beze změny // obsah citace uložený v $1 var text = ""JavaScript" je interpretovaný programovací jazyk."; var result = text.replace(quote, ""$1""; ) ; // "JavaScript" je interpretovaný programovací jazyk.

Důležité je poznamenat, že druhým argumentem pro náhradu() může být funkce, která dynamicky vypočítává náhradní řetězec.

Metoda zápas() je nejobecnější z metod třídy String, která používá regulární výrazy. Vezme regulární výraz jako svůj jediný argument (nebo převede svůj argument na regulární výraz předáním konstruktoru RegExp()) a vrátí pole obsahující výsledky hledání. Pokud je v regulárním výrazu nastaven příznak g, metoda vrátí pole všech shod přítomných v řetězci. Například:

// vrátí ["1", "2", "3"] var result = "1 plus 2 se rovná 3".match(/\d+/g);

Pokud regulární výraz neobsahuje příznak g, metoda match() neprovede globální vyhledávání; prostě to vypadá na první zápas. Match() však vrací pole, i když metoda neprovádí globální vyhledávání. V tomto případě je prvním prvkem pole nalezený podřetězec a všechny zbývající prvky jsou podvýrazy regulárního výrazu. Pokud tedy match() vrátí pole arr, pak arr bude obsahovat celý nalezený řetězec, arr podřetězec odpovídající prvnímu podvýrazu atd. Nakreslíme-li paralelu s metodou replace(), můžeme říci, že obsah $n je vložen do arr[n].

Podívejte se například na následující kód, který analyzuje adresu URL:

Var url = /(\w+):\/\/([\w.]+)\/(\S*)/; var text = "Navštivte naše webové stránky http://www..php"; var vysledek = text.match(url); if (výsledek != null) ( var fullurl = výsledek; // Obsahuje "http://www..php" var protokol = výsledek; // Obsahuje "http" var hostitel = výsledek; // Obsahuje "www..php ")

Je třeba poznamenat, že pro regulární výraz, který nemá nastaven příznak globálního vyhledávání g, metoda match() vrací stejnou hodnotu jako metoda exec() regulárního výrazu: vrácené pole má vlastnosti index a input, jak je popsáno v diskuzi o exec() níže.

Poslední z objektových metod String, která používá regulární výrazy, je rozdělit(). Tato metoda rozděluje řetězec, na kterém je volána, na pole podřetězců, přičemž používá argument jako oddělovač. Například:

"123,456,789".split(","); // Návrat ["123","456","789"]

Metoda split() může také převzít regulární výraz jako argument. Díky tomu je metoda výkonnější. Můžete například zadat oddělovač, který umožňuje libovolný počet mezer na obou stranách:

"1, 2, 3, 4, 5".split(/\s*,\s*/); // Návrat ["1","2","3","4","5"]

RegExp objekt

Jak již bylo zmíněno, regulární výrazy jsou reprezentovány jako objekty RegExp. Kromě konstruktoru RegExp() podporují objekty RegExp tři metody a několik vlastností.

Konstruktor RegExp() vezme jeden nebo dva řetězcové argumenty a vytvoří nový objekt RegExp. Prvním argumentem konstruktoru je řetězec obsahující tělo regulárního výrazu, tzn. text, který se musí objevit mezi znaky lomítka v literálu regulárního výrazu. Všimněte si, že řetězcové literály a regulární výrazy používají znak \ k reprezentaci escape sekvencí, takže při předávání regulárního výrazu jako řetězcového literálu konstruktoru RegExp() musíte nahradit každý znak \ dvojicí znaků \\.

Druhý argument pro RegExp() může chybět. Pokud je zadán, definuje příznaky regulárního výrazu. Musí to být jeden ze znaků g, i, m nebo kombinace těchto znaků. Například:

// Najde všechna pěticiferná čísla v řetězci. Poznámka // použití symbolů v tomto příkladu \\ var zipcode = new RegExp("\\d(5)", "g");

Konstruktor RegExp() je užitečný, když je regulární výraz generován dynamicky, a proto jej nelze reprezentovat pomocí doslovné syntaxe regulárního výrazu. Chcete-li například najít řetězec zadaný uživatelem, musíte za běhu vytvořit regulární výraz pomocí funkce RegExp().

Vlastnosti RegExp

Každý objekt RegExp má pět vlastností. Vlastnictví zdroj- řetězec pouze pro čtení obsahující text regulárního výrazu. Vlastnictví globální je booleovská hodnota pouze pro čtení, která určuje, zda je příznak g přítomen v regulárním výrazu. Vlastnictví ignoreCase je booleovská hodnota pouze pro čtení, která určuje, zda je příznak i přítomen v regulárním výrazu. Vlastnictví víceřádkový je booleovská hodnota pouze pro čtení, která určuje, zda je příznak m přítomen v regulárním výrazu. A poslední nemovitost lastIndex je celé číslo, které lze číst a zapisovat. U vzorů s příznakem g tato vlastnost obsahuje číslo pozice v řádku, na kterém by mělo začít další hledání. Jak je popsáno níže, používají jej metody exec() a test().

Metody RegExp

Objekty RegExp definují dvě metody, které provádějí porovnávání vzorů; chovají se podobně jako výše popsané metody třídy String. Hlavní metoda třídy RegExp používaná pro porovnávání vzorů je exec(). Je podobná dříve zmíněné metodě match() třídy String, kromě toho, že se jedná o metodu třídy RegExp, která přebírá řetězec jako argument, spíše než metodu třídy String, která přebírá argument RegExp.

Metoda exec() provede regulární výraz pro zadaný řetězec, tzn. hledá shodu v řetězci. Pokud není nalezena žádná shoda, metoda vrátí hodnotu null. Pokud je však nalezena shoda, vrátí stejné pole jako pole vrácené metodou match() pro vyhledávání bez příznaku g. Nulový prvek pole obsahuje řetězec, který odpovídá regulárnímu výrazu, a všechny následující prvky obsahují podřetězce, které odpovídají všem podvýrazům. Kromě toho majetek index obsahuje číslo pozice znaku, kterým začíná odpovídající fragment, a vlastnost vstup odkazuje na řádek, který byl prohledán.

Na rozdíl od match() metoda exec() vrací pole, jehož struktura nezávisí na přítomnosti příznaku g v regulárním výrazu. Dovolte mi připomenout, že při předávání globálního regulárního výrazu metoda match() vrací pole nalezených shod. A exec() vždy vrátí jednu shodu, ale poskytne o ní úplné informace. Když je funkce exec() volána na regulární výraz, který obsahuje příznak g, metoda nastaví vlastnost lastIndex objektu regulárního výrazu na číslo pozice znaku bezprostředně za nalezeným podřetězcem.

Když je exec() voláno podruhé na stejném regulárním výrazu, začne hledání u znaku, jehož pozice je určena ve vlastnosti lastIndex. Pokud exec() nenajde shodu, vlastnost lastIndex je nastavena na 0. (LastIndex můžete také kdykoli nastavit na nulu, což by mělo být provedeno ve všech případech, kdy vyhledávání skončí dříve, než je poslední shoda v jednom řádku nalezen a hledání začíná na jiném řádku se stejným objektem RegExp.) Toto speciální chování umožňuje opakované volání exec() za účelem opakování všech shod regulárního výrazu v řádku. Například:

Vzor var = /Java/g; var text = "JavaScript je zábavnější než Java!"; var výsledek; while((result = pattern.exec(text)) != null) ( console.log("Nalezeno "" + výsledek + """ + " na pozici " + result.index + "; další hledání začne na " + vzor .lastIndex);

Další metodou objektu RegExp je test(), což je mnohem jednodušší než metoda exec(). Vezme řetězec a vrátí hodnotu true, pokud řetězec odpovídá regulárnímu výrazu:

Vzor Var = /java/i; pattern.test("JavaScript"); // Návrat true

Volání test() je ekvivalentní volání exec(), které vrátí hodnotu true, pokud exec() vrátí něco jiného než null. Z tohoto důvodu se metoda test() při volání globálního regulárního výrazu chová stejně jako metoda exec(): začne hledat zadaný řetězec na pozici určené vlastností lastIndex, a pokud najde shodu , nastaví vlastnost lastIndex na číslo pozice znaku přímo vedle nalezené shody. Pomocí metody test() tedy můžete vytvořit smyčku procházení řádků stejným způsobem jako pomocí metody exec().

V JavaScriptu jsou regulární výrazy reprezentovány objekty RegExp. Objekty RegExp lze vytvořit pomocí konstruktoru RegExp(), ale častěji jsou vytvořeny pomocí speciální doslovné syntaxe. Stejně jako jsou řetězcové literály specifikovány jako znaky uzavřené v uvozovkách, literály regulárních výrazů jsou specifikovány jako znaky uzavřené do dvojice znaků lomítka / .

/pattern/flags new RegExp("vzor"[, možnosti vyhledávání])

vzor- regulární výraz pro vyhledávání (více o nahrazení později) a příznaky - řetězec libovolné kombinace znaků g (globální vyhledávání), i (velká a malá písmena nejsou důležitá) a m (víceřádkové vyhledávání). První metoda se používá často, druhá - někdy. Například dvě taková volání jsou ekvivalentní.

Možnosti vyhledávání

Při vytváření regulárního výrazu můžeme zadat další možnosti vyhledávání

Znaky v regulárních výrazech JavaScriptu

SymbolKorespondence
Alfanumerické znakyOdpovídají sami sobě
\0 Znak NUL (\u0000)
\tKarta (\u0009)
\nOdřádkování (\u000A)
\protiSvislá karta (\u000B)
\FPřeklad stránky (\u000C)
\rVrácení vozíku (\u000D)
\xnnZnak z latinské množiny určený hexadecimálním číslem nn; například \x0A je totéž jako \n
\uxxxxZnak Unicode určený hexadecimálním číslem xxxx; například \u0009 je stejné jako \t
\cXŘídicí znak "X", například sekvence \cJ je ekvivalentní znaku nového řádku \n
\ Pro běžné postavy – dělá je speciálními. Například výraz /s/ jednoduše hledá znak "s". A pokud vložíte \ před s, pak /\s/ již označuje znak mezery a naopak, pokud je znak speciální, například *, pak z něj \ udělá jen obyčejný znak „hvězdičky“. Například /a*/ hledá 0 nebo více po sobě jdoucích znaků "a". Chcete-li najít a s hvězdičkou "a*" - vložte \ před speciální. symbol: /a\*/ .
^ Označuje začátek vstupních dat. Pokud je nastaven příznak víceřádkového vyhledávání ("m"), spustí se také na začátku nového řádku, například /^A/ nenajde "A" v "A", ale najde první "A" v "A."
$ Označuje konec vstupních dat. Pokud je nastaven příznak víceřádkového vyhledávání, bude fungovat i na konci řádku. Například /t$/ nenajde "t" v "eater", ale najde ho v "eat".
* Označuje opakování 0 nebo vícekrát. Například /bo*/ najde "boooo" v "A ghost booooed" a "b" v "A bird whibled", ale nenajde nic v "A goat chrochtal".
+ Označuje opakování 1 nebo vícekrát. Ekvivalent k (1,). Například /a+/ bude odpovídat "a" v "candy" a všem "a" v "caaaaaaandy".
? Označuje, že prvek může nebo nemusí být přítomen. Například /e?le?/ bude odpovídat "el" v "angel" a "le" v "úhel", pokud je použito bezprostředně za jedním z kvantifikátorů * , + , ? , nebo () , pak specifikuje „nenasytné“ vyhledávání (opakující se minimální možný počet opakování, až k nejbližšímu dalšímu prvku vzoru), na rozdíl od výchozího „hladového“ režimu, ve kterém je počet opakování maximální, i když se shoduje i další prvek vzoru Navíc , ? používá se v náhledu, který je popsán v tabulce pod (?=) , (?!) a (?:) .
. (Desetinná čárka) představuje jakýkoli znak jiný než nový řádek: \n \r \u2028 nebo \u2029. (můžete použít [\s\S] k vyhledání libovolného znaku, včetně nových řádků). Například /.n/ bude odpovídat "an" a "on" v "ne, jablko je na stromě", ale ne "ne".
(x)Najde x a zapamatuje si. Tomu se říká „paměťové závorky“. Například /(foo)/ najde a zapamatuje si "foo" v "foo bar." Nalezený podřetězec je uložen v poli výsledků hledání nebo v předdefinovaných vlastnostech objektu RegExp: $1, ..., $9 Navíc závorky spojují to, co je v nich obsaženo, do jediného prvku vzoru. Například (abc)* - opakujte abc 0 nebo vícekrát.
(?:x)Najde x, ale nepamatuje si, co najde. Říká se tomu „paměťové závorky“. Nalezený podřetězec není uložen ve vlastnostech pole výsledků a RegExp Stejně jako všechny závorky spojují to, co je v nich, do jediného podvzoru.
x(?=y)Najde x pouze v případě, že za x následuje y. Například /Jack(?=Sprat)/ bude odpovídat "Jack", pouze pokud bude následovat "Sprat". /Jack(?=Sprat|Frost)/ bude odpovídat "Jack" pouze v případě, že bude následovat "Sprat" nebo "Frost". Ve výsledku vyhledávání se však neobjeví ani "Sprat" ani "Frost".
x(?!y)Najde x pouze v případě, že za x nenásleduje y. Například /\d+(?!\.)/ bude odpovídat číslu pouze v případě, že za ním nenásleduje desetinná čárka. /\d+(?!\.)/.exec("3.141") najde 141, ale ne 3,141.
x|yNajde x nebo y. Například /zelená|červená/ bude odpovídat „zelené“ v „zeleném jablku“ a „červené“ v „červeném jablku“.
(n)Kde n je kladné celé číslo. Najde přesně n opakování předchozího prvku. Například /a(2)/ nenajde "a" v "candy", ale najde jak a v "caandy", tak první dvě a v "caaandy."
(n,)Kde n je kladné celé číslo. Najde n nebo více opakování prvku. Například /a(2,) nenajde "a" v "candy", ale najde všechna "a" v "caandy" a "caaaaaaandy."
(n,m)Kde n a m jsou kladná celá čísla. Najděte od n do m opakování prvku.
Znaková sada. Najde kterýkoli z uvedených znaků. Mezery můžete označit pomocí pomlčky. Například - totéž jako . Shoduje se s "b" v "hrudí" a "a" a "c" v "ache".
[^xyz]Jakýkoli jiný znak, než který je uveden v sadě. Můžete také určit rozpětí. Například [^abc] je totéž jako [^a-c] . Najde "r" v "hrudníku" a "h" v "chop."
[\b]Najde znak backspace. (Neplést s \b .)
\bVyhledá (latinsky) hranici slova, například mezeru. (Neplést s [\b]). Například /\bn\w/ bude odpovídat "ne" v "poledne"; /\wy\b/ najde "ly" v "možná včera."
\BNeoznačuje hranici slova. Například /\w\Bn/ bude odpovídat "on" v "poledne" a /y\B\w/ bude odpovídat "ye" v "možná včera."
\cXKde X je písmeno od A do Z. Označuje řídicí znak v řetězci. Například /\cM/ představuje znak Ctrl-M.
\dnajde číslo z libovolné abecedy (naše je Unicode). Použijte k nalezení pouze běžných čísel. Například /\d/ nebo // bude odpovídat "2" v "B2 je číslo sady."
\DVyhledá nečíselný znak (všechny abecedy). [^0-9] je ekvivalent pro běžná čísla. Například /\D/ nebo /[^0-9]/ bude odpovídat "B" v "B2 je číslo sady."
\sNajde jakýkoli znak mezery, včetně mezery, tabulátoru, nového řádku a dalších znaků mezer Unicode. Například /\s\w*/ bude odpovídat "bar" v "foo bar."
\SNajde jakýkoli znak kromě mezer. Například /\S\w*/ bude odpovídat "foo" v "foo bar."
\protiSvislý znak tabulátoru.
\wNajde jakýkoli znak slova (latinská abeceda), včetně písmen, číslic a podtržítek. Ekvivalent. Například /\w/ bude odpovídat „a“ v „jablko“, „5“ v „5,28 $“ a „3“ v „3D“.
\WNajde jakýkoli ne-(latinský) verbální znak. Ekvivalentní [^A-Za-z0-9_] . Například /\W/ a /[^$A-Za-z0-9_]/ budou stejně odpovídat „%“ v „50 %.

Práce s regulárními výrazy v Javascriptu

Práce s regulárními výrazy v Javascriptu je realizována metodami třídy String

exec(regexp) - najde všechny shody (záznamy v běžném vzoru) v řetězci. Vrátí pole (pokud existuje shoda) a aktualizuje vlastnost regulární výraz nebo hodnotu null, pokud není nic nalezeno. S modifikátorem g - pokaždé, když je tato funkce zavolána, vrátí další shodu po předchozí nalezené - to je implementováno udržováním offsetového indexu posledního vyhledávání.

match(regexp) - najít část řetězce pomocí vzoru. Pokud je zadán modifikátor g, pak match() vrátí pole všech shod nebo null (spíše než prázdné pole). Bez modifikátoru g tato funkce funguje jako exec();

test(regexp) - funkce kontroluje řetězec, zda odpovídá vzoru. Vrátí hodnotu true, pokud existuje shoda, a false, pokud neexistuje žádná shoda.

split(regexp) - Rozdělí řetězec, na který je volán, na pole podřetězců, přičemž argument použije jako oddělovač.

nahradit(regexp, mix) - metoda vrací upravený řetězec v souladu se šablonou (regulární výraz). Prvním parametrem regulárního výrazu může být také řetězec, nikoli regulární výraz. Bez modifikátoru g metoda v řádku nahradí pouze první výskyt; s modifikátorem g - dochází ke globální záměně, tzn. všechny výskyty daného řádku se změní.

mix - náhradní šablona, ​​může přijímat hodnoty řetězce, náhradní šablony, funkce (název funkce).

Speciální znaky v náhradním řetězci

Výměna přes funkci

Pokud zadáte funkci jako druhý parametr, provede se pro každou shodu. Funkce může dynamicky generovat a vracet substituční řetězec. Prvním parametrem funkce je nalezený podřetězec. Pokud je prvním argumentem, který se má nahradit, objekt RegExp, pak dalších n parametrů obsahuje vnořené závorky. Poslední dva parametry jsou pozice v řádku, kde došlo ke shodě, a samotný řádek.

Třída RegExp v JavaScriptu je regulární výraz – objekt, který popisuje vzor znaků. Objekty RegExp se obvykle vytvářejí pomocí speciální doslovné syntaxe uvedené níže, ale lze je vytvořit také pomocí konstruktoru RegExp().

Syntax// pomocí speciální doslovné syntaxe var regex = /pattern /flags ;// pomocí konstruktoru

var regex = new RegExp("vzor", "příznaky"); var regex = new RegExp(/vzor /, "flags");

Hodnoty parametrů:

Příznaky regulárních výrazůVlajka
PopisG Umožňuje vám najít všechny shody namísto zastavení po první shodě ().
globální zápas vlajkyi Umožňuje shodu bez rozlišení velkých a malých písmen ().
ignorovat příznak případuPárování se provádí ve více řádcích. Úvodní a koncové znaky (^ a $) se zpracovávají na více řádcích, což znamená, že ke shodě dochází na začátku nebo na konci každého řádku (oddělovače \n nebo \r), a nikoli pouze na začátku nebo konci celého řádku ( víceřádkový příznak).
uVzor bude interpretován jako sekvence bodů kódu Unicode ( unicode vlajka).
yKe shodě dochází u indexu, na který ukazuje vlastnost lastIndex tohoto regulárního výrazu, zatímco shoda se neprovádí na pozdějším nebo dřívějším indexu ( lepkavá vlajka).

Znakové sady

Metaznaky

SymbolVlajka
. Umožňuje vám najít jeden znak jiný než nový řádek nebo znak konce řádku (\n, \r, \u2028 nebo \u2029).
\dUmožňuje najít číselný symbol v základní latinské abecedě. Ekvivalent použití znakové sady.
\DUmožňuje najít jakýkoli znak, který není číslem v základní latinské abecedě. Ekvivalent znakové sady [^0-9].
\sUmožňuje vám najít jeden prázdný znak. Mezery se týkají mezery, tabulátoru, odřádkování, odřádkování a dalších mezer Unicode. Ekvivalent znakové sady [\f\n\r\t\v​\u00a0\u1680​\u180e\u2000​\u2001\u2002​\u2003\u2004​\u2005\u2006​\u2007\u2009 u200a​ \u2028\u2029​\u202f\u205f​\u3000].
\SUmožňuje vám najít jeden znak, který není prázdný. Mezery se týkají mezery, tabulátoru, odřádkování, odřádkování a dalších mezer Unicode. Ekvivalent znakové sady [^ \f\n\r\t\v​\u00a0\u1680​\u180e\u2000​\u2001\u2002​\u2003\u2004​\u2005\u2006​\u2007\u2009 \u200a ​\u2028\u2029​\u202f\u205f​\u3000].
[\b]Umožňuje najít znak backspace (speciální znak \b, U+0008).
\0 Umožňuje najít symbol 0 (nula).
\nUmožňuje vám najít znak nového řádku.
\FUmožňuje vám najít znak zdroje stránky.
\rUmožňuje najít znak návratu vozíku.
\tUmožňuje najít vodorovný znak tabulátoru.
\protiUmožňuje najít svislý znak tabulátoru.
\wUmožňuje najít jakýkoli alfanumerický znak v základní latinské abecedě včetně podtržítek. Ekvivalentní znakové sadě.
\WUmožňuje najít jakýkoli znak, který není znakem ze základní latinské abecedy. Ekvivalentní znakové sadě [^a-Za-z0-9_].
\cXUmožňuje najít řídicí znak v řetězci. Kde X je písmeno od A do Z. Například /\cM/ představuje znak Ctrl-M.
\xhhUmožňuje najít znak pomocí hexadecimální hodnoty (hh je dvoumístná hexadecimální hodnota).
\uhhhhUmožňuje najít znak pomocí kódování UTF-16 (hhhh je čtyřmístná hexadecimální hodnota).
\u(hhhh) nebo
\u(hhhhh)
Umožňuje vám najít znak s hodnotou Unicode U+hhhh nebo U+hhhhh (hexadecimální hodnota). Pouze když je uveden příznak u.
\ Označuje, že následující znak je speciální a neměl by být vykládán doslovně. U znaků, které jsou obvykle interpretovány zvláštním způsobem, určuje, že následující znak není speciální a měl by být interpretován doslovně.

Omezení

Kvantifikátory

SymbolVlajka
n*Shoda nastane u libovolného řetězce obsahujícího nula nebo více výskytů znaku n.
n+Ke shodě dochází s jakýmkoli řetězcem obsahujícím alespoň jeden znak n.
n?Ke shodě dojde u libovolného řetězce s předchozím prvkem n nula nebo jednou.
n(x)Odpovídá libovolnému řetězci obsahujícímu posloupnost znaků n určitý počet krát x. X
n(x,) x výskyty předchozího prvku n. X musí být kladné celé číslo.
n(x, y)Odpovídá libovolnému řetězci obsahujícímu alespoň x, ale ne více než s y výskyty předchozího prvku n. X A y musí být kladná celá čísla.
n*?
n+?
n??
n(x)?
n(x,)?
n(x,y)?
Srovnání probíhá analogicky s kvantifikátory *, +, ? a (...), hledá se však minimální možné srovnání. Výchozí nastavení je "chamtivý" režim, ? na konci kvantifikátoru umožňuje nastavit „non-chamtivý“ režim, ve kterém se porovnání opakuje co nejméně.
x(?=y)Umožňuje porovnávat x, pouze pokud pro x by měl y.
x(?!y)Umožňuje porovnávat x, pouze pokud pro x neměl by y.
x|yK porovnání dochází s kteroukoli ze zadaných alternativ.

Seskupování a zpětné odkazy

SymbolVlajka
(x)Umožňuje najít symbol x a zapamatujte si výsledek porovnání ("zachycení závorek"). Odpovídající podřetězec lze volat z výsledných prvků pole ..., [n] nebo z vlastností předdefinovaného objektu RegExp $1 ..., $9.
(?:x)Umožňuje najít symbol x, ale nepamatuje si výsledek zápasu ("nezachycující závorky"). Odpovídající podřetězec nelze volat z výsledných prvků pole ..., [n] nebo z vlastností předdefinovaného objektu RegExp $1 ..., $9.
\nNávratový odkaz na poslední podřetězec, který se shoduje s n-tým v závorkách v regulárním výrazu (číslování závorek jde zleva doprava). n musí být kladné celé číslo.

Někteří lidé, když se potýkají s problémem, si pomyslí: "Ach, použiji regulární výrazy." Nyní mají dva problémy.
Jamie Zawinski

Yuan-Ma řekl: „Je potřeba hodně síly na řezání dřeva přes vlákno dřeva. Programování napříč strukturou problému vyžaduje hodně kódu.
Mistr Yuan-Ma, „Kniha programování“

Programovací nástroje a techniky přežívají a šíří se chaotickým evolučním způsobem. Někdy nepřežijí krásní a brilantní, ale prostě ti, kteří ve svém oboru fungují dostatečně dobře – například pokud jsou integrováni do jiné úspěšné technologie.

V této kapitole si probereme takový nástroj – regulární výrazy. Toto je způsob, jak popsat vzory v řetězcových datech. Vytvářejí malý, samostatný jazyk, který je součástí JavaScriptu a mnoha dalších jazyků a nástrojů.

Pravidelné jízdní řády jsou velmi zvláštní a velmi užitečné. Jejich syntaxe je záhadná a jejich programovací rozhraní JavaScriptu je neohrabané. Ale je to mocný nástroj pro zkoumání a manipulaci s řetězci. Jakmile je pochopíte, stanete se efektivnějšími programátory.

Vytvoření regulárního výrazu

Regular – typ objektu. Lze jej vytvořit voláním konstruktoru RegExp nebo napsáním požadované šablony ohraničené lomítky.

Var re1 = new RegExp("abc"); var re2 = /abc/;

Oba tyto regulární výrazy představují stejný vzor: znak „a“ následovaný znakem „b“ následovaný znakem „c“.

Pokud použijete konstruktor RegExp, pak se vzor zapíše jako běžný řetězec, takže platí všechna pravidla týkající se zpětných lomítek.

Druhá položka, kde je vzor mezi lomítky, zachází se zpětnými lomítky odlišně. Za prvé, protože vzor končí lomítkem, musíme před lomítko, které chceme zahrnout do našeho vzoru, vložit zpětné lomítko. Navíc zpětná lomítka, která nejsou součástí speciálních znaků, jako je \n, budou zachována (spíše než ignorována jako v řetězcích) a změní význam vzoru. Některé znaky, jako je otazník nebo plus, mají v regulárních výrazech speciální význam, a pokud takový znak potřebujete najít, musí mu předcházet i zpětné lomítko.

Var osmnáctPlus = /osmnáct\+/;

Abyste věděli, kterým znakům musí předcházet lomítko, musíte se naučit seznam všech speciálních znaků v regulárních výrazech. To zatím není možné, takže v případě pochybností stačí dát zpětné lomítko před jakýkoli znak, který není písmenem, číslem nebo mezerou.

Kontrola zápasů

Pravidelní mají několik metod. Nejjednodušší je test. Pokud mu předáte řetězec, vrátí booleovskou hodnotu označující, zda řetězec obsahuje výskyt daného vzoru.

Console.log(/abc/.test("abcde")); // → true console.log(/abc/.test("abxde")); // → nepravda

Pravidelná sekvence skládající se pouze z nespeciálních znaků je jednoduše sekvencí těchto znaků. Pokud je abc kdekoli v řádku, který testujeme (nejen na začátku), test vrátí hodnotu true.

Hledá se soubor postav

Můžete také zjistit, zda řetězec obsahuje abc pomocí indexOf. Pravidelné vzory umožňují jít dále a vytvářet složitější vzory.

Řekněme, že potřebujeme najít nějaké číslo. Když do regulárního výrazu vložíme množinu znaků do hranatých závorek, znamená to, že tato část výrazu odpovídá libovolnému ze znaků v závorce.

Oba výrazy jsou v řádcích obsahujících číslo.

Console.log(//.test("v roce 1992")); // → true console.log(//.test("v roce 1992")); // → pravda

V hranatých závorkách se pomlčka mezi dvěma znaky používá k určení rozsahu znaků, kde sekvence je určena kódováním Unicode. Znaky od 0 do 9 jsou tam jen v řadě (kódy od 48 do 57), takže je zachytí všechny a shoduje se s libovolným číslem.

Několik skupin znaků má své vlastní vestavěné zkratky.

\d Libovolné číslo
\w Alfanumerický znak
\s Znak mezery (mezera, tabulátor, nový řádek atd.)
\D není číslo
\W není alfanumerický znak
\S není znak mezery
. libovolný znak kromě odřádkování

Můžete tedy nastavit formát data a času jako 01/30/2003 15:20 s následujícím výrazem:

Var dateTime = /\d\d-\d\d-\d\d\d\d \d\d:\d\d/; console.log(dateTime.test("30-01-2003 15:20")); // → true console.log(dateTime.test("30-Jan-2003 15:20")); // → nepravda

Vypadá to hrozně, že? Je zde příliš mnoho zpětných lomítek, což ztěžuje pochopení vzoru. Později to trochu vylepšíme.

V hranatých závorkách lze také použít zpětná lomítka. Například [\d.] znamená libovolné číslo nebo tečku. Všimněte si, že tečka uvnitř hranatých závorek ztrácí svůj zvláštní význam a stává se jednoduše tečkou. Totéž platí pro další speciální znaky, jako je +.

Sadu znaků můžete invertovat - to znamená, že potřebujete najít jakýkoli znak kromě těch, které jsou v sadě - umístěním znaménka ^ bezprostředně za úvodní hranatou závorku.

Var notBinary = /[^01]/; console.log(notBinary.test("1100100010100110")); // → false console.log(notBinary.test("1100100010200110")); // → pravda

Opakující se části šablony

Víme, jak najít jedno číslo. Co když potřebujeme najít celé číslo – posloupnost jedné nebo více číslic?

Pokud za něco v pravidelném pořadí vložíte znaménko +, bude to znamenat, že tento prvek lze opakovat více než jednou. /\d+/ znamená jednu nebo více číslic.

Console.log(/"\d+"/.test(""123"")); // → true console.log(/"\d+"/.test("""")); // → false console.log(/"\d*"/.test(""123"")); // → true console.log(/"\d*"/.test("""")); // → pravda

Hvězdička * má téměř stejný význam, ale umožňuje, aby se vzor vyskytoval nulakrát. Pokud za něčím následuje hvězdička, pak to nikdy nebrání tomu, aby byl vzor v řádku – jen se tam objeví nulakrát.

Otazník činí část vzoru volitelnou, což znamená, že se může objevit nula nebo jednou. V následujícím příkladu se může objevit znak u, ale vzor se shoduje, i když tomu tak není.

Var soused = /soused?r/; console.log(neighbor.test("soused")); // → true console.log(neighbor.test("neighbor")); // → pravda

Složené závorky se používají k určení přesného počtu opakování vzoru. (4) za prvkem znamená, že se musí v řádku objevit 4krát. Můžete také zadat mezeru: (2,4) znamená, že prvek se musí vyskytnout alespoň 2krát a ne více než 4krát.

Další verze formátu data a času, kde jsou povoleny dny, měsíce a hodiny o jedné nebo dvou číslicích. A také je o něco čitelnější.

Var dateTime = /\d(1,2)-\d(1,2)-\d(4) \d(1,2):\d(2)/; console.log(dateTime.test("30-1-2003 8:45")); // → pravda

Můžete použít mezery s otevřeným koncem vynecháním jednoho z čísel. (,5,) znamená, že vzor se může vyskytnout od nuly do pětikrát, a (5,) znamená od pěti nebo více.

Seskupování podvýrazů

Chcete-li použít operátory * nebo + na více prvcích najednou, můžete použít závorky. Část regulárního výrazu uzavřená v závorkách je z pohledu operátorů považována za jeden prvek.

Var cartoonCrying = /boo+(hoo+)+/i; console.log(cartoonCrying.test("Boohoooohoohooo")); // → pravda

První a druhé plus platí pouze pro druhé o v bu a hoo. Třetí + odkazuje na celou skupinu (hoo+) a najde jednu nebo více takových sekvencí.

Písmeno i na konci výrazu způsobuje, že regulární výraz nerozlišuje velká a malá písmena – takže B odpovídá b.

Zápasy a skupiny

Testovací metoda je nejjednodušší metodou pro kontrolu regulárních výrazů. Pouze vám řekne, zda byla nalezena shoda nebo ne. Regulari mají také metodu exec, která vrátí null, pokud nebylo nic nalezeno, a jinak vrátí objekt s informací o shodě.

Var match = /\d+/.exec("jedna dva 100"); console.log(match); // → ["100"] console.log(match.index); // → 8

Objekt vrácený exec má vlastnost index, která obsahuje číslo znaku, ze kterého došlo ke shodě. Obecně objekt vypadá jako pole řetězců, kde prvním prvkem je řetězec, u kterého byla zkontrolována shoda. V našem příkladu to bude posloupnost čísel, kterou jsme hledali.

Řetězce mají metodu shody, která funguje v podstatě stejným způsobem.

Console.log("jedna dva 100".match(/\d+/)); // → ["100"]

Pokud regulární výraz obsahuje podvýrazy seskupené v závorkách, objeví se v poli také text, který odpovídá těmto skupinám. Prvním prvkem je vždy úplná shoda. Druhá je část, která se shodovala s první skupinou (ta, jejíž závorky se vyskytly jako první), pak s druhou skupinou a tak dále.

Var quotedText = /"([^"]*)"/; console.log(quotedText.exec("řekla "ahoj"")); // → [""ahoj"", "ahoj"]

Pokud skupina není vůbec nalezena (například pokud za ní následuje otazník), její pozice v poli není definována. Pokud se skupina shoduje několikrát, bude v poli pouze poslední zápas.

Console.log(/bad(ly)?/.exec("špatný")); // → ["špatný", nedefinováno] console.log(/(\d)+/.exec("123")); // → ["123", "3"]

Skupiny jsou užitečné pro získávání částí řetězců. Pokud nechceme jen kontrolovat, zda má řetězec datum, ale extrahovat jej a vytvořit objekt reprezentující datum, můžeme posloupnosti čísel uzavřít do závorek a datum vybrat z výsledku exec.

Nejprve ale malá odbočka, ve které se naučíme preferovaný způsob ukládání data a času v JavaScriptu.

Typ data

JavaScript má standardní objektový typ pro data – konkrétněji okamžiky v čase. Jmenuje se Date. Pokud jednoduše vytvoříte objekt data pomocí new, získáte aktuální datum a čas.

Console.log(new Date()); // → Ne 9. listopadu 2014 00:07:57 GMT+0300 (CET)

Můžete také vytvořit objekt obsahující daný čas

Console.log(nové datum(2015, 9, 21)); // → St Oct 21 2015 00:00:00 GMT+0300 (CET) console.log(new Date(2009, 11, 9, 12, 59, 59, 999)); // → St. prosince 09 2009 12:59:59 GMT+0300 (CET)

JavaScript používá konvenci, kdy čísla měsíců začínají nulou a čísla dnů začínají jedničkou. To je hloupé a směšné. Dávejte pozor.

Poslední čtyři argumenty (hodiny, minuty, sekundy a milisekundy) jsou volitelné a pokud chybí, jsou nastaveny na nulu.

Časová razítka jsou uložena jako počet milisekund, které uplynuly od začátku roku 1970. Pro doby před rokem 1970 se používají záporná čísla (je to kvůli časové konvenci Unixu, která byla vytvořena v této době). Metoda getTime objektu data vrací toto číslo. Je přirozeně velký.
console.log(new Date(2013, 11, 19).getTime()); // → 1387407600000 console.log(new Date(1387407600000)); // → Čt 19. prosince 2013 00:00:00 GMT+0100 (CET)

Pokud dáte konstruktoru Date jeden argument, bude se s ním zacházet jako s tímto počtem milisekund. Aktuální hodnotu milisekund můžete získat vytvořením objektu Date a voláním metody getTime nebo voláním funkce Date.now.

Objekt Date má metody getFullYear, getMonth, getDate, getHours, getMinutes a getSeconds pro načtení jeho součástí. Existuje také metoda getYear, která vrací poměrně zbytečný dvoumístný kód jako 93 nebo 14.

Uzavřením příslušných částí šablony do závorek můžeme přímo z řetězce vytvořit objekt data.

Funkce findDate(string) ( var dateTime = /(\d(1,2))-(\d(1,2))-(\d(4))/; var match = dateTime.exec(string); return new Datum(číslo(shoda), Číslo(shoda) - 1, Číslo(shoda) ) console.log(findDate("30-1-2003")); // → Čt 30. ledna 2003 00:00:00 GMT+0100 (CET)

Hranice slov a řádků

Bohužel findDate stejně šťastně vydoluje nesmyslné datum 00-1-3000 z řetězce "100-1-30000". Shoda může nastat kdekoli v řetězci, takže v tomto případě bude jednoduše začínat na druhém znaku a končit na předposledním znaku.

Pokud potřebujeme vynutit shodu, aby zabrala celý řetězec, použijeme značky ^ a $. ^ odpovídá začátku řádku a $ odpovídá konci. Proto /^\d+$/ odpovídá řetězci obsahujícímu pouze jednu nebo více číslic, /^!/ odpovídá řetězci začínajícímu vykřičníkem a /x^/ neodpovídá žádnému řetězci (nesmí být x).

Pokud se naopak chceme ujistit, že datum začíná a končí na hranici slova, použijeme značku \b. Hranicí slova může být začátek nebo konec řádku nebo jakékoli místo v řádku, kde je na jedné straně alfanumerický znak \w a na druhé nealfanumerický znak.

Console.log(/cat/.test("concatenate")); // → true console.log(/\bcat\b/.test("concatenate")); // → nepravda

Všimněte si, že štítek hranice není symbol. Je to prostě omezení, což znamená, že ke shodě dojde pouze v případě, že je splněna určitá podmínka.

Šablony s možností výběru

Řekněme, že potřebujete zjistit, zda text neobsahuje pouze číslo, ale číslo, za kterým následuje prase, kráva nebo kuře v jednotném nebo množném čísle.

Bylo by možné napsat tři regulární výrazy a zkontrolovat je jeden po druhém, ale existuje lepší způsob. Symbol | označuje výběr mezi vzory nalevo a napravo od něj. A můžeme říci následující:

Var počet zvířat = /\b\d+ (prase|kráva|kuře)s?\b/; console.log(animalCount.test("15 prasat")); // → true console.log(animalCount.test("15 prasátek")); // → nepravda

Závorky vymezují část vzoru, na kterou se vztahuje |, a mnoho takových operátorů lze umístit jeden za druhým, aby bylo možné vybrat z více než dvou možností.

Vyhledávač

Regulární výrazy lze chápat jako vývojové diagramy. Následující diagram popisuje nedávný příklad dobytka.

Výraz odpovídá řetězci, pokud je možné najít cestu z levé strany diagramu doprava. Pamatujeme si aktuální pozici v řádku a pokaždé, když procházíme obdélníkem, kontrolujeme, zda část úsečky bezprostředně za naší pozicí v něm odpovídá obsahu obdélníku.

To znamená, že kontrola shody našeho běžného znaku v řetězci „3 prasata“ při procházení vývojového diagramu vypadá takto:

Na pozici 4 je hranice slova a míjíme první obdélník
- od 4. pozice najdeme číslo a projdeme druhým obdélníkem
- na pozici 5 se jedna cesta uzavírá zpět před druhý obdélník a druhá jde dále k obdélníku s mezerou. Máme mezeru, ne číslo a volíme druhou cestu.
- nyní jsme na pozici 6, začátku „prasat“ a na trojitém rozvětvení cest. V řadě není žádná „kráva“ nebo „kuře“, ale „prase“, takže volíme tuto cestu.
- na pozici 9 za trojitým rozvětvením jedna cesta obchází „s“ a jde do posledního hraničního obdélníku slova a druhá prochází „s“. Máme "s", takže jdeme tam.
- na pozici 10 jsme na konci řádku a může se shodovat pouze hranice slova. Konec úsečky je považován za hranici a procházíme posledním obdélníkem. A nyní jsme úspěšně našli naši šablonu.

Regulární výrazy v podstatě fungují tak, že algoritmus začíná na začátku řetězce a snaží se tam najít shodu. V našem případě je tam hranice slova, takže projde prvním obdélníkem - ale není tam žádné číslo, takže narazí na druhý obdélník. Pak se přesune na druhý znak v řetězci a snaží se tam najít shodu... A tak dále, dokud nenajde shodu nebo se nedostane na konec řetězce, v takovém případě není nalezena žádná shoda.

Zpětné provize

Regulární výraz /\b(+b|\d+|[\da-f]h)\b/ odpovídá buď binárnímu číslu následovanému ab, desítkovému číslu bez přípony nebo hexadecimálnímu číslu (čísla 0 až 9 nebo symboly od a do h), následované h. Příslušný diagram:

Při hledání shody se může stát, že algoritmus zvolí horní cestu (binární číslo), i když takové číslo v řetězci není. Pokud je tam například řádek „103“, je jasné, že až po dosažení čísla 3 algoritmus pochopí, že je na špatné cestě. Obecně platí, že řádek odpovídá pravidelné sekvenci, jen ne v tomto vláknu.

Poté se algoritmus vrátí zpět. Na rozcestí si pamatuje aktuální pozici (v našem případě je to začátek řádku hned za slovem hranice), abyste se mohli vrátit a zkusit jinou cestu, pokud zvolená nefunguje. U řetězce „103“ se po setkání s trojkou vrátí zpět a pokusí se projít desetinnou cestu. To bude fungovat, takže bude nalezena shoda.

Algoritmus se zastaví, jakmile nalezne úplnou shodu. To znamená, že i když může být vhodných několik možností, použije se pouze jedna z nich (v pořadí, v jakém se objevují v pravidelném pořadí).

Zpětné sledování nastává při použití operátorů opakování, jako jsou + a *. Pokud hledáte /^.*x/ v řetězci "abcxe", část regulárního výrazu.* se pokusí spotřebovat celý řetězec. Algoritmus si pak uvědomí, že potřebuje také „x“. Protože za koncem řetězce není žádné „x“, algoritmus se pokusí vyhledat shodu posunutím o jeden znak zpět. Po abcx také není x, pak se to vrátí zpět, tentokrát na podřetězec abc. A po řádku najde x a oznámí úspěšnou shodu, na pozicích 0 až 4.

Můžete napsat pravidelnou rutinu, která povede k několika vrácením zpět. K tomuto problému dochází, když vzor může odpovídat vstupu mnoha různými způsoby. Pokud například uděláme chybu při psaní regulárního výrazu pro binární čísla, můžeme omylem napsat něco jako /(+)+b/.

Pokud by algoritmus hledal takový vzor v dlouhém řetězci 0s a 1s, který by neměl na konci „b“, prošel by nejprve vnitřní smyčkou, dokud by mu nedošly číslice. Pak si všimne, že na konci není žádné „b“, vrátí se o jednu pozici zpět, projde vnější smyčkou, znovu to vzdá, pokusí se převrátit zpět do jiné polohy po vnitřní smyčce... A bude pokračovat vyhledávat tímto způsobem pomocí obou smyček. To znamená, že množství práce s každým znakem řádku se zdvojnásobí. I pro několik desítek postav bude hledání shody trvat velmi dlouho.

nahradit metoda

Řetězce mají metodu nahrazení, která může nahradit část řetězce jiným řetězcem.

Console.log("táta".replace("p", "m")); // → mapa

Prvním argumentem může být také regulární výraz, v takovém případě je nahrazen první výskyt regulárního výrazu v řádku. Když je k regulárnímu výrazu přidána možnost „g“ (globální), budou nahrazeny všechny výskyty, nejen první

Console.log("Borobudur".replace(//, "a")); // → Barobudur console.log("Borobudur".replace(//g, "a")); // → Barabadar

Mělo by smysl předat možnost „nahradit vše“ samostatným argumentem nebo samostatnou metodou, jako je nahradit vše. Ale bohužel se tato možnost přenáší prostřednictvím samotného běžného systému.

Plná síla regulárních výrazů se projeví, když použijeme odkazy na skupiny nalezené v řetězci specifikovaném v regulárním výrazu. Máme například řádek obsahující jména lidí, jedno jméno na řádek, ve formátu „Příjmení, Jméno“. Pokud je potřebujeme prohodit a odstranit čárku, abychom získali „First Name Last Name“, napíšeme následující:

Console.log("Hopper, Grace\nMcCarthy, John\nRitchie, Dennis" .replace(/([\w ]+), ([\w ]+)/g, "2 $ 1")); // → Grace Hopper // John McCarthy // Dennis Ritchie

$1 a $2 v náhradním řádku odkazují na skupiny znaků v závorkách. $1 se nahradí textem, který odpovídá první skupině, $2 druhou skupinou atd., až do výše $9. Celá shoda je obsažena v proměnné $&.

Jako druhý argument můžete také předat funkci. Pro každou náhradu bude zavolána funkce, jejíž argumenty budou nalezené skupiny (a celá odpovídající část řádku), a její výsledek bude vložen do nového řádku.

Jednoduchý příklad:

Var s = "cia a fbi"; console.log(s.replace(/\b(fbi|cia)\b/g, function(str) ( return str.toUpperCase(); ))); // → CIA a FBI

Zde je jeden zajímavější:

Var stock = "1 citron, 2 zelí a 101 vajec"; funkce minusJedna(shoda, množství, jednotka) ( množství = Číslo(částka) - 1; jestliže (částka == 1) // zbývá pouze jedno, odstraňte "s" na konci unit = unit.slice(0, unit. délka - 1 else if (částka == 0) částka = "ne"; vrácená částka + " " + jednotka ) console.log(stock.replace(/(\d+) (\w+)/g, minusJedna) ); // → žádný citron, 1 zelí a 100 vajec

Kód vezme řetězec, najde všechny výskyty čísel následovaných slovem a vrátí řetězec s každým číslem zmenšeným o jednu.

Skupina (\d+) přejde do argumentu množství a (\w+) přejde do argumentu jednotky. Funkce převede částku na číslo - a to vždy funguje, protože náš vzor je \d+. A pak provede změny slova, v případě, že zbývá pouze 1 položka.

Chamtivost

Je snadné použít nahradit k napsání funkce, která odstraní všechny komentáře z kódu JavaScript. Zde je první pokus:

Funkce stripComments(code) ( return code.replace(/\/\/.*|\/\*[^]*\*\//g, ""); ) console.log(stripComments("1 + /*) 2 */3")); // → 1 + 3 console.log(stripComments("x = 10;// deset!")); // → x = 10; console.log(stripComments("1 /* a */+/* b */ 1")); // → 11

Část před operátorem "or" odpovídá dvěma lomítkům následovaným libovolným počtem znaků kromě nových řádků. Část, která odstraňuje víceřádkové komentáře, je složitější. Používáme [^], tzn. jakýkoli znak, který není prázdný, jako způsob, jak najít jakýkoli znak. Nemůžeme použít tečku, protože komentáře bloku pokračují na novém řádku a znak nového řádku neodpovídá tečce.

Ale výstup předchozího příkladu je nesprávný. Proč?

Část [^]* se nejprve pokusí zachytit co nejvíce postav. Pokud kvůli tomu další část pravidelné sekvence nenajde shodu, vrátí se o jeden znak zpět a zkusí to znovu. V příkladu se algoritmus pokusí zachytit celý řádek a poté se vrátí zpět. Po vrácení 4 znaků zpět najde v řádku */ - a to jsme nechtěli. Chtěli jsme zachytit pouze jeden komentář a ne jít na konec řádku a najít poslední komentář.

Z tohoto důvodu říkáme, že operátory opakování (+, *, ? a ()) jsou nenasytné, což znamená, že nejprve chytnou, co mohou, a pak se vrátí zpět. Pokud položíte otázku po operátorovi jako je tento (+?, *?, ??, ()?), změní se na nenažrané a začnou hledat nejmenší možné výskyty.

A to je to, co potřebujeme. Tím, že hvězdičku přinutíme najít shodu v minimálním možném počtu znaků v řádku, spotřebujeme pouze jeden blok komentářů a nic víc.

Funkce stripComments(code) ( return code.replace(/\/\/.*|\/\*[^]*?\*\//g, ""); ) console.log(stripComments("1 /*) a */+/* b */ 1")); // → 1 + 1

Mnoho chyb se vyskytuje při použití chamtivých operátorů místo těch, které nejsou chamtivé. Při použití operátoru opakování vždy nejprve zvažte operátor, který není chamtivý.

Dynamické vytváření objektů RegExp

V některých případech je přesný vzor v době psaní kódu neznámý. Například budete muset v textu vyhledat jméno uživatele a uzavřít ho podtržítky. Vzhledem k tomu, že jméno budete znát až po spuštění programu, nemůžete použít lomítko.

Ale můžete vytvořit řetězec a použít konstruktor RegExp. Zde je příklad:

Jméno var = "harry"; var text = "A Harry má na čele jizvu."; var regexp = new RegExp("\\b(" + jméno + ")\\b", "gi"); console.log(text.replace(regexp, "_$1_")); // → A _Harry_ má na čele jizvu.

Při vytváření hranic slov musíme používat dvojitá lomítka, protože je píšeme na normálním řádku, a ne v pravidelném pořadí s dopřednými lomítky. Druhý argument k RegExp obsahuje možnosti pro regulární výrazy - v našem případě „gi“, tj. globální a nerozlišuje malá a velká písmena.

Ale co když je jméno „dea+hlrd“ (pokud je náš uživatel kulhatzker)? Ve výsledku dostaneme nesmyslný regulární výraz, který v řetězci nenajde shody.

Před jakoukoli postavu, která se nám nelíbí, můžeme přidat zpětná lomítka. Před písmena nemůžeme přidávat zpětná lomítka, protože \b nebo \n jsou speciální znaky. Ale můžete bez problémů přidat lomítka před jakékoli nealfanumerické znaky.

Název var = "dea+hlrd"; var text = "Tento dea+hlrd obtěžuje každého."; var escaped = name.replace(/[^\w\s]/g, "\\$&"); var regexp = new RegExp("\\b(" + escaped + ")\\b", "gi"); console.log(text.replace(regexp, "_$1_")); // → Tohle _dea+hlrd_ všechny naštvalo.

metoda vyhledávání

Metodu indexOf nelze použít s regulárními výrazy. Existuje však metoda vyhledávání, která pouze očekává regulární výraz. Stejně jako indexOf vrací index prvního výskytu nebo -1, pokud se žádný nevyskytuje.

Console.log(" slovo".search(/\S/)); // → 2 console.log(" ".search(/\S/)); // → -1

Bohužel neexistuje způsob, jak říci metodě, aby hledala shodu začínající na určitém offsetu (jak to můžete udělat s indexOf). To by bylo užitečné.

vlastnost lastIndex

Metoda exec také neposkytuje pohodlný způsob, jak zahájit vyhledávání z dané pozice v řetězci. Ale dává to nepohodlný způsob.

Objekt regulárního výrazu má vlastnosti. Jedním z nich je source, který obsahuje řetězec. Dalším je lastIndex, který za určitých podmínek řídí, kde začne další hledání výskytů.

Mezi tyto podmínky patří, že musí být přítomna globální volba g a že vyhledávání musí být provedeno pomocí metody exec. Rozumnějším řešením by bylo jednoduše umožnit předání dalšího argumentu exec, ale rozumnost není základním rysem rozhraní regulárního výrazu JavaScriptu.

Var vzor = /y/g; pattern.lastIndex = 3; var match = pattern.exec("xyzzy"); console.log(match.index); // → 4 console.log(pattern.lastIndex); // → 5

Pokud bylo hledání úspěšné, volání exec aktualizuje vlastnost lastIndex tak, aby ukazovala na pozici za nalezeným výskytem. Pokud nedošlo k úspěchu, lastIndex se nastaví na nulu – stejně jako lastIndex nově vytvořeného objektu.

Při použití globální běžné proměnné a vícenásobných volání exec mohou tyto automatické aktualizace lastIndex způsobit problémy. Váš běžný server může začít hledat od pozice, která zůstala po předchozím hovoru.

Var číslice = /\d/g; console.log(digit.exec("tady to je: 1")); // → ["1"] console.log(digit.exec("a teď: 1")); // → null

Dalším zajímavým efektem možnosti g je to, že mění způsob, jakým metoda shody funguje. Při volání s touto volbou místo vracení pole podobného výsledku exec najde všechny výskyty vzoru v řetězci a vrátí pole nalezených podřetězců.

Console.log("Banana".match(/an/g)); // → ["an", "an"]

Buďte tedy opatrní s globálními regulárními proměnnými. Případy, kdy jsou potřeba – nahraďte hovory nebo místa, kde konkrétně používáte lastIndex – jsou pravděpodobně všechny případy, ve kterých by se měly používat.

Cykly výskytu

Typickým úkolem je iterovat všechny výskyty vzoru v řetězci, aby měl přístup k objektu match v těle smyčky pomocí lastIndex a exec.

Var input = "Řádek se 3 čísly... 42 a 88."; číslo var = /\b(\d+)\b/g; var zápas; while (match = číslo.exec(vstup)) console.log("Nalezeno ", shoda, " na ", shoda.index); // → Nalezeno 3 od 14 // Nalezeno 42 od 33 // Nalezeno 88 od 40

Využívá toho, že hodnotou přiřazení je hodnota, která se přiřazuje. Použitím match = re.exec(input) jako podmínky v cyklu while hledáme na začátku každé iterace, uložíme výsledek do proměnné a cyklus ukončíme, když jsou nalezeny všechny shody.

Analýza INI souborů

Na závěr kapitoly se podívejme na problém s použitím regulárních výrazů. Představte si, že píšeme program, který automaticky sbírá informace o našich nepřátelích přes internet. (Nebudeme psát celý program, jen část, která čte soubor nastavení. Omlouváme se.) Soubor vypadá takto:

Searchengine=http://www.google.com/search?q=$1 zlomyslnost=9.7 ; před komentáře je umístěn středník; každá sekce odkazuje na jiného nepřítele celé jméno=Larry Doe typ=kindergarten bull website=http://www.geocities.com/CapeCanaveral/11451 fullname=Gargamel type=evil wizard outputdir=/home/marijn/enemies/gargamel

Přesný formát souboru (který je poměrně široce používaný a obvykle se nazývá INI) je následující:

Prázdné řádky a řádky začínající středníkem jsou ignorovány
- řádky v hranatých závorkách začínají novou sekci
- řádky obsahující alfanumerický identifikátor následovaný = přidat nastavení v této části

Vše ostatní jsou nesprávná data.

Naším úkolem je převést takový řetězec na pole objektů, každý s vlastností name a polem nastavení. Jeden objekt je potřeba pro každou sekci a další je potřeba pro globální nastavení nad souborem.

Protože je třeba soubor analyzovat řádek po řádku, je dobré začít rozdělením souboru na řádky. K tomu jsme použili string.split("\n") v kapitole 6. Některé operační systémy nepoužívají pro zalomení řádku jeden znak \n, ale dva - \r\n. Protože metoda rozdělení používá regulární výrazy jako argument, můžeme rozdělit řádky pomocí výrazu /\r?\n/, což umožňuje jak jednotlivé \n, tak \r\n mezi řádky.

Funkce parseINI(string) ( // Začněme objektem obsahujícím nastavení nejvyšší úrovně var currentSection = (název: null, pole: ); var category = ; string.split(/\r?\n/).forEach(function (line ) ( var match; if (/^\s*(;.*)?$/.test(line)) ( return; ) else if (match = line.match(/^\[(.*)\ ]$ /)) ( currentSection = (název: shoda, pole: ); category.push (currentSection); ) else if (match = line.match(/^(\w+)=(.*)$/)) ( aktuálníSekce.push((název: shoda, hodnota: shoda) else ( throw new Error("Řádek "" + řádek + "" obsahuje neplatná data."); ) ));

Kód prochází všemi řádky a aktualizuje objekt aktuální sekce „aktuální sekce“. Nejprve zkontroluje, zda lze řádek ignorovat pomocí regulárního výrazu /^\s*(;.*)?$/. Dokážete si představit, jak to funguje? Část mezi závorkami odpovídá komentářům, co? dělá to tak, že běžný znak bude odpovídat také řádkům obsahujícím pouze mezery.

Pokud řádek není komentářem, kód zkontroluje, zda nezačíná novou sekci. Pokud ano, vytvoří se nový objekt pro aktuální sekci, ke kterému se přidají další nastavení.

Poslední smysluplnou možností je, že řetězec je normální nastavení, v takovém případě je přidán k aktuálnímu objektu.

Pokud nefunguje žádná z možností, funkce vyvolá chybu.

Všimněte si, jak časté používání ^ a $ zajišťuje, že výraz odpovídá celému řetězci, nikoli jen jeho části. Pokud je nepoužíváte, kód bude obecně fungovat, ale někdy bude produkovat podivné výsledky a chybu bude obtížné vystopovat.

Konstrukce if (match = string.match(...)) je podobná triku s použitím přiřazení jako podmínky v cyklu while. Často nevíte, že volání shody bude úspěšné, takže k výslednému objektu můžete přistupovat pouze uvnitř bloku if, který jej kontroluje. Abychom nenarušili krásný řetězec if kontrol, přiřadíme výsledek hledání k proměnné a toto přiřazení rovnou použijeme jako kontrolu.

Mezinárodní symboly

Vzhledem k původně jednoduché implementaci jazyka a následnému zafixování takové implementace „v žule“ jsou regulární výrazy JavaScriptu hloupé se znaky, které se v angličtině nenacházejí. Například znak „písmeno“ může být z pohledu regulárních výrazů JavaScriptu jedním z 26 písmen anglické abecedy a z nějakého důvodu také podtržítko. Písmena jako é nebo β, která jsou jasně písmena, se neshodují s \w (a budou odpovídat \W, což je nepísmeno).

V podivném zvratu historicky \s (mezera) odpovídá všem znakům, které jsou v Unicode považovány za mezery, včetně věcí, jako je mezera nebo oddělovač mongolských samohlásek.

Některé implementace regulárních výrazů v jiných jazycích mají speciální syntaxi pro vyhledávání speciálních kategorií znaků Unicode, jako jsou „všechna velká písmena“, „všechna interpunkce“ nebo „řídicí znaky“. Existují plány na přidání takových kategorií do JavaScriptu, ale zřejmě nebudou brzy implementovány.

Sečteno a podtrženo

Reguláry jsou objekty, které představují vyhledávací vzory v řetězcích. K vyjádření těchto vzorů používají vlastní syntaxi.

/abc/ Posloupnost znaků
// Libovolný znak ze seznamu
/[^abc]/ Libovolný znak kromě znaků ze seznamu
// Libovolný znak z intervalu
/x+/ Jeden nebo více výskytů vzoru x
/x+?/ Jeden nebo více výskytů, nezištný
/x*/ Žádný nebo více výskytů
/x?/ Nula nebo jeden výskyt
/x(2,4)/ Od dvou do čtyř výskytů
/(abc)/ Skupina
/a|b|c/ Jakýkoli z několika vzorů
/\d/ Libovolné číslo
/\w/ Libovolný alfanumerický znak („písmeno“)
/\s/ Libovolný znak mezery
/./ Libovolný znak kromě nových řádků
/\b/ Hranice slova
/^/ Začátek řádku
/$/ Konec řádku

Regulární výraz má testovací metodu pro kontrolu, zda je vzor v řetězci. Existuje metoda exec, která vrací pole obsahující všechny nalezené skupiny. Pole má vlastnost index, která obsahuje číslo znaku, ze kterého došlo ke shodě.

Řetězce mají metodu shody pro shodu vzorů a metodu vyhledávání, která vrací pouze počáteční pozici výskytu. Metoda nahrazení může nahradit výskyty vzoru jiným řetězcem. Kromě toho můžete předat funkci k nahrazení, která vytvoří náhradní řádek na základě šablony a nalezených skupin.

Regulární znaky mají nastavení, která se zapisují za koncové lomítko. Volba i nerozlišuje velká a malá písmena regulárního výrazu a volba g jej činí globálním, což mimo jiné způsobí, že metoda nahradit nahradí všechny nalezené výskyty, nejen ten první.

Konstruktor RegExp lze použít k vytvoření regulárních výrazů z řetězců.

Regulátory jsou ostrý nástroj s nepohodlnou rukojetí. Některé úkoly značně zjednodušují a při řešení jiných, složitých problémů se mohou stát nezvládnutelnými. Součástí učení se používat regulární výraz je umět odolat pokušení nacpat do něj úkol, pro který není určen.

Cvičení

Nevyhnutelně se při řešení problémů setkáte s nepochopitelnými případy a možná si někdy budete zoufat, když uvidíte nepředvídatelné chování některých regulárních výrazů. Někdy pomůže nastudovat chování běžného motoru prostřednictvím online služby, jako je debuggex.com, kde můžete vidět jeho vizualizaci a porovnat ji s požadovaným efektem.
Pravidelný golf
„Golf“ v kódu je hra, kde potřebujete vyjádřit daný program v minimálním počtu znaků. Pravidelný golf je praktickým cvičením psaní co nejmenších štamgastů k nalezení daného vzoru, a to jedině.

Pro každý z podřádků napište regulární výraz, abyste zkontrolovali jejich umístění v řádku. Běžný stroj by měl najít pouze tyto zadané podřetězce. Nedělejte si starosti s hranicemi slov, pokud to není výslovně uvedeno. Když máte fungující pravidelný vzor, ​​zkuste jej snížit.

Auto a kočka
- pop a rekvizita
- fretka, trajekt a ferrari
- Jakékoli slovo končící na ious
- Mezera následovaná tečkou, čárkou, dvojtečkou nebo středníkem.
- Slovo delší než šest písmen
- Slovo bez písmen e

// Zadejte své regulární výrazy ověřit(/.../, ["moje auto", "zlé kočky"], ["camper", "vysoké umění"]); ověřit(/.../, ["popkultura", "šílené rekvizity"], ["plop"]); ověřit(/.../, ["fretka", "trajekt", "ferrari"], ["ferrum", "převod A"]); ověřit(/.../, ["jak lahodné", "prostorný pokoj"], ["zničující", "vědomí"]); ověřit(/.../, ["špatná interpunkce."], ["uniknout tečku"]); ověřit(/.../, ["hottenottententen"], ["ne", "hotten totten tenten"]); ověřit(/.../, ["červený ptakopysk", "kolébavé hnízdo"], ["zemní postel", "učící se opice"]); funkce ověřit(regexp, ano, ne) ( // Ignorovat nedokončená cvičení if (regexp.source == "...") return; yes.forEach(function(s) ( if (!regexp.test(s)) console .log("Nenalezeno "" + s + """ )); no.forEach(funkce(y) ( if (regexp.test(s)) console.log("Neočekávaný výskyt "" + s + " "" ));

Citáty v textu
Řekněme, že jste napsali příběh a použili jednoduché uvozovky k označení dialogu. Nyní chcete nahradit uvozovky v dialogu dvojitými uvozovkami a ponechat jednoduché uvozovky ve zkratkách pro slova jako nejsou.

Vymyslete vzor, ​​který rozlišuje mezi těmito dvěma způsoby použití uvozovek, a napište volání metody nahradit, která provede nahrazení.

Zase čísla
Posloupnosti čísel lze nalézt pomocí jednoduchého regulárního výrazu /\d+/.

Napište výraz, který najde pouze čísla zapsaná ve stylu JavaScriptu. Musí podporovat možné mínus nebo plus před číslem, desetinnou čárku a vědecký zápis 5e-3 nebo 1E10 – opět s možným plusem nebo mínusem. Všimněte si také, že před nebo za tečkou nemusí být nutně čísla, ale číslo se nemůže skládat z jedné tečky. To znamená, že 0,5 nebo 5 jsou platná čísla, ale jedna tečka sama o sobě není.

// Zde zadejte pravidelnou sekvenci. číslo var = /^...$/; // Testy: ["1", "-1", "+15", "1.55", ".5", "5.", "1.3e2", "1E-4", "1e+12"] .forEach(funkce(y) ( if (!číslo.test(y)) console.log("Nenalezeno "" + s + """); )); ["1a", "+-1", "1.2.3", "1+1", "1e4.5", ".5.", "1f5", "."].forEach(funkce) ( if (číslo.test(y)) console.log("Nesprávně přijato "" + s + """); ));

Regex nebo regulární výrazy jsou pro začátečníky zastrašující, ale pro každého programátora jsou nezbytné. Pojďme pochopit regulární výrazy pomocí 5 jednoduchých příkladů s JavaScriptem.

Pokud máte problém a hodláte ho vyřešit regulárními výrazy, máte nyní dva problémy. Existuje rčení. Regulární výrazy nalezené v kódu někdy vyvolávají strach a nenávist u lidí, kteří je neznají.

Ale ve skutečnosti je jakýkoli regulární výraz pouze šablonovým výrazem, který dokáže vyřešit problém celé funkce na jednom řádku. Chcete-li však sestavit regulární výraz, musíte vzít v úvahu soubor přísných pravidel, ve kterých se začátečník může splést a udělat chyby.

Odpovídající postavy

Nejzákladnější regulární výrazy jsou ty, které odpovídají jednotlivým znakům. Zde jsou jejich pravidla:

1. Tečka (.) odpovídá libovolnému znaku. Pokud potřebujete vyhledat konkrétní bod, musíte jej opustit znakem „\“ (\.).

2. Otazník (?) označuje, že předchozí znak je volitelný. Chcete-li vyhledat otazník samotný v řetězci, musí být také escapován pomocí "\" (\?).

var text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit lest. Donec convallis dignissim ligula, et rutrum est elat vistibulum eu."; // Postačí „elit“ i „elat“. Tečka znamená, že se hodí jakýkoli symbol. var regex = /el.t/g; console.log(text.match(regulární výraz)); // "est" a "lest" budou fungovat stejně dobře. Díky otazníku je "l" nepovinné. var regex2 = /l?est/g; console.log(text.match(regulární výraz2));

var text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit lest. Donec convallis dignissim ligula, et rutrum est elat vistibulum eu.";

// Postačí „elit“ i „elat“. Tečka znamená, že se hodí jakýkoli symbol.

var regex = /el.t/g ;

utěšit. log(text. shoda(regulární výraz));

// "est" a "lest" budou fungovat stejně dobře. Otazník činí "l" volitelným.

var regex2 = /l?est/g ;

utěšit. log(text. shoda(regulární výraz2));

Spojte více znaků

Sada je jeden nebo více znaků uzavřených v závorkách, například . Tento výraz bude hledat pouze tuto sadu znaků v řetězci – v tomto příkladu pouze a, b nebo c. Naopak můžete vyhledávat výskyty libovolných symbolů kromě použití symbolu „^“. [^abc] bude odpovídat libovolnému znaku, který není a, b nebo c. Můžete také zadat rozsah znaků nebo čísel, například , .

Existují vestavěné znakové sady, které usnadňují psaní regulárních výrazů. Říká se jim zkratky nebo zkratka. Místo toho můžete například napsat \D. Existují zkratky pro další znaky (včetně čísel a podtržítek) - \w a \W, stejně jako pro mezery - \s a \S.

// Fungovat bude pouze "kočka" a "can", nikoli "auto". var text = "kočičí konzerva"; console.log(text.match(/ca/g)); // Projde vše kromě cat a can (je tam symbol ^) console.log(text.match(/ca[^tn]/g)); // Další příklad, kdy projdou pouze čísla text = "Chtěl bych 8 šálků kávy, prosím."; console.log("Kolik šálků: " + text.match(//g)); // Jednodušší způsob pomocí zkratky \d console.log("Kolik šálků: " + text.match(/\d/g)); // Předá vše kromě čísel console.log(text.match(/\D/g));

// Fungovat bude pouze "kočka" a "can", nikoli "auto".

var text = "kočičí konzerva" ;

utěšit. log(text. shoda(/ca/g));

// Projde vše kromě kočky a plechovky (je tam symbol ^)

utěšit. log (text . shoda (/ca[^tn]/g ) ) ;

// Další příklad, kdy projdou pouze čísla

text = "Chtěl bych 8 šálků kávy, prosím.";

utěšit. log ("Kolik šálků: " + text . shoda (//g) ) ;

// Jednodušší způsob pomocí zkratky \d

utěšit. log ("Kolik kelímků: " + text . shoda (/\d/g ) ) ;

// Projde vše kromě čísel

utěšit. log(text. shoda(/\D/g));

Odpovídající slova

Ve většině případů je potřeba hledat celá slova, nikoli jednotlivé znaky. To se provádí pomocí modifikátorů (+) a (-), které opakují znak nebo sadu znaků.

Sčítání (X) udává přesný počet opakování, (x, y) – rozsah (x a y jsou čísla).

Navíc existuje speciální vzor \b, který odpovídá hranicím na koncích slov.

var text = "Ahoj lidé z roku 1974. Přicházím z budoucnosti. V roce 2014 máme laserová děla, vznášedla a žijeme na Měsíci!"; // Najde roky. \d+ bude odpovídat jednomu nebo více znakům var yearRegex = /\d+/g; console.log("Roky: ", text.match(rokRegex)); // Najde všechny věty. Naše věty začínají velkým písmenem a končí tečkou nebo vykřičníkem. var větaRegex = /.+?(\.|!)/g; console.log("Sentences: ", text.match(sentenceRegex)); // Najde všechna slova začínající na "h". Vyhovují nám velká i malá písmena, proto k definici hranice slova používáme modifikátor i // \b. var hWords = /\bh\w+/ig; console.log("H Slova: ", text.match(hWords)); // Najde všechna slova od 4 do 6 znaků var findWords = /\b\w(4,6)\b/g; console.log("Slova mezi 4 a 6 znaky: ", text.match(findWords)); // Hledání slov delších než 5 znaků console.log("Slova 5 znaků nebo delší: ", text.match(/\b\w(5,)\b/g)); // Najde slova dlouhá přesně 6 znaků console.log("Slova přesně 6 znaků dlouhá: ", text.match(/\b\w(6)\b/g));

var text = "Ahoj lidé z roku 1974. Pocházím z budoucnosti. V roce 2014 máme laserová děla, vznášedla a žijeme na Měsíci!";

// Najde roky. \d+ odpovídá jednomu nebo více znakům

var yearRegex = /\d+/g ;

utěšit. log ( "Roky: " , text . shoda ( rokRegex ) ) ;

// Najde všechny věty. Naše věty začínají velkým písmenem a končí tečkou nebo vykřičníkem.

var větaRegex = /.+?(\.|!)/g ;

utěšit. log("Sentences: ", text. match(sentenceRegex));

// Najde všechna slova začínající na "h". Vyhovují nám velká i malá písmena, proto používáme modifikátor i

// \b k určení hranic slov.

var hWords = /\bh\w+/i g ;

utěšit. log ( "H Slova: " , text . shoda ( hWords ) );

// Najde všechna slova od 4 do 6 znaků

var findWords = /\b\w(4,6)\b/g ;

utěšit. log( "Slova mezi 4 a 6 znaky: ", text . match(findWords));

// Hledání slov delších než 5 znaků

utěšit. log ("Slova 5 znaků nebo delší: " , text . shoda (/\b\w(5,)\b/g ) ) ;

// Najděte slova dlouhá přesně 6 znaků

utěšit. log( "Slova přesně 6 znaků dlouhá: ", text . shoda (/\b\w(6)\b/g ) );

Ověření celého řetězce

V JavaScriptu lze takové výrazy použít k ověření uživatelského vstupu z textových polí. K ověření řetězců se používá regulární regulární výraz svázaný se začátkem a koncem textového fragmentu s použitím výrazů ^ ​​(začátek řádku) a $ (konec řádku) pro tento účel. Tyto symboly zajistí, že vzor, ​​který napíšete, bude pokrývat celou délku textu, a nikoli pouze jeho část.

V tomto případě navíc používáme metodu test() objektu regulárního výrazu, která při testování, zda regulární výraz odpovídá řetězci, vrací hodnotu true nebo false.

// Máme pole řetězců, pojďme najít odkazy..com/", "123461", "https://site/?s=google", "http://není platná url", "abc http: / /invalid.url/" ]; var regex = /^https?:\/\/[\w\/?.&-=]+$/; var urls = ; for(var i = 0; i< strings.length; i++){ if(regex.test(strings[i])){ // Валидная ссылка urls.push(strings[i]); } } console.log("Valid URLs: ", urls);

// Máme pole řetězců, pojďme najít odkazy.

var strings = [

"https://site/",

"toto není URL" ,

"https://google.com/",

"123461" ,

"https://site/?s=google" ,

"http://není platná adresa URL" ,

"abc http://invalid.url/"

var regex = / ^ https ? : \ / \ / [ \ w \ / ? . & -= ] + $ / ;

var url = ;

for (var i = 0; i< strings . length ; i ++ ) {

if (regulární výraz . test (řetězce [ i ] ) ) (

adresy URL. push(strings[i]);

utěšit. log("Platné adresy URL: ", adresy URL);

Hledat a nahradit

Dalším běžným úkolem, který je usnadněn používáním regulárních výrazů, je hledání a nahrazování textu.




Nahoru