Căutare Javascript prin expresie regulată. Aplicarea unei expresii regulate unui șir. Verificare regExp - testare e-mail

În JavaScript, expresiile regulate sunt reprezentate de obiecte RegExp. Obiectele RegExp pot fi create folosind constructorul RegExp(), dar mai des sunt create folosind o sintaxă literală specială. La fel cum literalele șir sunt specificate ca caractere cuprinse între ghilimele, literalele expresii regulate sunt specificate ca caractere incluse într-o pereche de caractere bară oblică / .

/pattern/flags new RegExp(„model”[, opțiuni de căutare])

model- o expresie obișnuită pentru căutare (mai multe despre înlocuire mai târziu) și steaguri - un șir de orice combinație de caractere g (căutare globală), i (măjuscule nu sunt importante) și m (căutare pe mai multe linii). Prima metodă este folosită des, a doua - uneori. De exemplu, două astfel de apeluri sunt echivalente.

optiuni de cautare

Când creăm o expresie regulată, putem specifica opțiuni suplimentare căutare

Caractere din expresiile regulate JavaScript

SimbolCorespondenţă
Caractere alfanumericeCorespunde lor înșiși
\0 Caracter NUL (\u0000)
\tFila (\u0009)
\nFlux de linie (\u000A)
\vFilă verticală (\u000B)
\fTraducerea paginii (\u000C)
\rRetur transport (\u000D)
\xnnUn caracter din setul latin, specificat prin numărul hexazecimal nn; de exemplu, \x0A este la fel cu \n
\uxxxxCaracter Unicode specificat de numărul hexazecimal xxxx; de exemplu, \u0009 este același cu \t
\cXCaracterul de control „X”, de exemplu, secvența \cJ este echivalentă cu caracterul newline \n
\ Pentru personajele obișnuite - le face speciale. De exemplu, expresia /s/ caută pur și simplu caracterul „s”. Și dacă puneți \ înainte de s, atunci /\s/ indică deja un caracter de spațiu Și invers, dacă caracterul este special, de exemplu *, atunci \ îl va face doar un caracter „asterisc” obișnuit. De exemplu, /a*/ caută 0 sau mai multe caractere consecutive „a”. Pentru a găsi un cu asterisc „a*” - pune \ în fața specialului. simbol: /a\*/ .
^ Indică începutul datelor de intrare. Dacă indicatorul de căutare pe mai multe linii ("m") este setat, se va declanșa și la începutul unei noi linii. De exemplu, /^A/ nu va găsi "A" în "un A", dar va găsi primul „A” în „An A”.
$ Indică sfârșitul datelor de intrare. Dacă este setat indicatorul de căutare pe mai multe linii, va funcționa și la sfârșitul liniei. De exemplu, /t$/ nu va găsi „t” în „eater”, dar îl va găsi în „eat”.
* Indică repetarea de 0 sau de mai multe ori. De exemplu, /bo*/ va găsi „buuuuuuuuuuuuuuuluuuuuuuuuuuuuulhului” în „A fantomă huiduită” și „b” în „A bird warbled”, dar nu va găsi nimic în „O capră a mormăit”.
+ Indică repetarea de 1 sau mai multe ori. Echivalent cu (1,). De exemplu, /a+/ se va potrivi cu „a” din „bomboane” și cu toate „a” din „caaaaaaandy”.
? Indică faptul că elementul poate fi prezent sau nu. De exemplu, /e?le?/ se va potrivi cu „el” în „înger” și „le” în „unghi”. , sau () , apoi specifică o căutare „non-lacomă” (repetând numărul minim posibil de ori, la cel mai apropiat element următor al modelului), spre deosebire de modul implicit „lacom”, în care numărul de repetări este maxim, chiar dacă elementul următor modelul este, de asemenea, potrivit. utilizat în previzualizare, care este descrisă în tabel de sub (?=) , (?!) și (?:) .
. (Punctul zecimal) reprezintă orice caracter, altul decât o linie nouă: \n \r \u2028 sau \u2029. (puteți folosi [\s\S] pentru a căuta orice caracter, inclusiv linii noi). De exemplu, /.n/ se va potrivi cu „an” și „on” în „nu, un măr este pe copac”, dar nu „nu”.
(X)Găsește x și își amintește. Aceasta se numește „paranteze de memorie”. De exemplu, /(foo)/ va găsi și își va aminti „foo” în „foo bar”. Subșirul găsit este stocat în matricea rezultatelor căutării sau în proprietățile predefinite ale obiectului RegExp: $1, ..., $9 În plus, parantezele combină ceea ce este conținut în ele într-un singur element de model. De exemplu, (abc)* - repetă abc 0 sau de mai multe ori.
(?:X)Găsește x, dar nu își amintește ce găsește. Aceasta se numește „paranteze de memorie”. Subșirul găsit nu este stocat în matricea de rezultate și în proprietățile RegExp. Ca ​​toate parantezele, ele combină ceea ce este în ele într-un singur submodel.
x(?=y)Găsește x numai dacă x este urmat de y. De exemplu, /Jack(?=Sprat)/ se va potrivi doar cu „Jack” dacă este urmat de „Sprat”. /Jack(?=Sprat|Frost)/ se va potrivi doar cu „Jack” dacă este urmat de „Sprat” sau „Frost”. Cu toate acestea, nici „Sprat” și nici „Frost” nu vor apărea în rezultatul căutării.
X y)Găsește x numai dacă x nu este urmat de y. De exemplu, /\d+(?!\.)/ se va potrivi doar cu un număr dacă nu este urmat de un punct zecimal. /\d+(?!\.)/.exec("3.141") va găsi 141, dar nu 3.141.
x|yGăsește x sau y. De exemplu, /verde|roșu/ se va potrivi cu „verde” în „măr verde” și „roșu” în „măr roșu”.
(n)Unde n este un număr întreg pozitiv. Găsește exact n repetări ale elementului precedent. De exemplu, /a(2)/ nu va găsi „a” în „bomboane”, dar va găsi atât a în „caandy”, cât și primele două a în „caaandy”.
(n,)Unde n este un număr întreg pozitiv. Găsește n sau mai multe repetări ale unui element. De exemplu, /a(2,) nu va găsi „a” în „bomboane”, dar va găsi toate „a” în „caandy” și în „caaaaaaandy”.
(n,m)Unde n și m sunt numere întregi pozitive. Găsiți de la n la m repetări ale elementului.
Set de caractere. Găsește oricare dintre personajele enumerate. Puteți indica spațierea folosind o liniuță. De exemplu, - la fel ca . Se potrivește „b” în „piept” și „a” și „c” în „durere”.
[^xyz]Orice caracter altul decât cele specificate în set. De asemenea, puteți specifica un interval. De exemplu, [^abc] este același cu [^a-c] . Găsește „r” în „piept” și „h” în „chop”.
[\b]Găsește caracterul backspace. (A nu se confunda cu \b .)
\bGăsește o limită a unui cuvânt (latină), cum ar fi un spațiu. (A nu se confunda cu [\b]). De exemplu, /\bn\w/ se va potrivi cu „nu” în „noonday”; /\wy\b/ va găsi „ly” în „posibil ieri”.
\BNu indică o limită de cuvânt. De exemplu, /\w\Bn/ se va potrivi cu „on” în „noonday”, iar /y\B\w/ se va potrivi cu „ye” în „eventual ieri”.
\cXUnde X este o literă de la A la Z. Indică un caracter de control într-un șir. De exemplu, /\cM/ reprezintă caracterul Ctrl-M.
\dgăsește un număr din orice alfabet (al nostru este Unicode). Utilizați pentru a găsi numai numere obișnuite. De exemplu, /\d/ sau // se va potrivi cu „2” din „B2 este numărul suită”.
\DGăsește un caracter nenumeric (toate alfabetele). [^0-9] este echivalentul pentru numerele regulate. De exemplu, /\D/ sau /[^0-9]/ se va potrivi cu „B” din „B2 este numărul suitei”.
\sGăsește orice caracter de spațiu alb, inclusiv spațiu, tabulator, linie nouă și alte caractere de spațiu alb Unicode. De exemplu, /\s\w*/ se va potrivi cu „bar” în „foo bar”.
\SGăsește orice caracter, cu excepția spațiului alb. De exemplu, /\S\w*/ se va potrivi cu „foo” în „foo bar”.
\vCaracter de filă verticală.
\wGăsește orice caracter de cuvânt (alfabet latin), inclusiv litere, cifre și caractere de subliniere. Echivalent. De exemplu, /\w/ se va potrivi cu „a” în „măr”, „5” în „5,28 USD” și „3” în „3D”.
\WGăsește orice caracter verbal non-(latin). Echivalent cu [^A-Za-z0-9_] . De exemplu, /\W/ și /[^$A-Za-z0-9_]/ se vor potrivi în mod egal cu „%” în „50%”.

Lucrul cu expresii regulate în Javascript

Lucrul cu expresii regulate în Javascript este implementat prin metodele clasei String

exec(regexp) - găsește toate potrivirile (intrările din modelul obișnuit) într-un șir. Returnează o matrice (dacă există o potrivire) și actualizează proprietatea regexp, sau null dacă nu se găsește nimic. Cu modificatorul g - de fiecare dată când această funcție este apelată, va returna următoarea potrivire după cea anterioară găsită - aceasta este implementată prin menținerea unui index de offset al ultimei căutări.

match(regexp) - găsiți o parte dintr-un șir folosind un model. Dacă este specificat modificatorul g, atunci match() returnează o matrice cu toate potrivirile sau null (mai degrabă decât o matrice goală). Fără modificatorul g, această funcție funcționează ca exec();

test(regexp) - funcția verifică un șir pentru a se potrivi cu un model. Returnează adevărat dacă există o potrivire și false dacă nu există potrivire.

split(regexp) - Împarte șirul la care este apelat într-o matrice de subșiruri, folosind argumentul ca delimitator.

replace(regexp, mix) - metoda returnează un șir modificat în conformitate cu șablonul (expresie regulată). Primul parametru al expresiei regulate poate fi, de asemenea, un șir, mai degrabă decât o expresie regulată. Fără modificatorul g, metoda din linie înlocuiește doar prima apariție; cu modificatorul g - se întâmplă înlocuire globală, adică toate aparițiile unei linii date sunt modificate. mix - șablon de înlocuire, poate accepta valorile unui șir, șablon de înlocuire, funcție (numele funcției).

Caractere speciale în șirul de înlocuire

Înlocuire prin funcție

Dacă specificați o funcție ca al doilea parametru, aceasta este executată pentru fiecare potrivire. O funcție poate genera și returna dinamic un șir de substituție. Primul parametru al funcției este subșirul găsit. Dacă primul argument de înlocuit este un obiect RegExp, atunci următorii n parametri conțin paranteze imbricate potriviri. Ultimii doi parametri sunt poziția în linia în care a avut loc potrivirea și linia în sine.

Clasa RegExp din JavaScript este o expresie regulată - un obiect care descrie un model de caractere. Obiectele RegExp sunt create de obicei folosind sintaxa literală specială prezentată mai jos, dar pot fi create și folosind constructorul RegExp().

Sintaxă

// folosind sintaxă literală specială var regex = /pattern /flags ; // folosind constructorul var regex = new RegExp ("model", "steaguri"); var regex = new RegExp(/pattern /, „steaguri „);

Valorile parametrilor:

Steaguri de expresie regulată

SteagDescriere
gVă permite să găsiți toate potrivirile în loc să vă opriți după prima potrivire ( steag de meci global).
iPermite potrivirea fără majuscule ( ignora flagul cazului).
mPotrivirea se face pe mai multe rânduri. Caracterele de început și de sfârșit (^ și $) sunt procesate pe mai multe linii, ceea ce înseamnă că potrivirea are loc la începutul sau la sfârșitul fiecărei linii (delimitatoare \n sau \r), și nu doar începutul sau sfârșitul întregii linii ( steag multilinie).
uModelul va fi interpretat ca o secvență de puncte de cod Unicode ( steag unicode).
yPotrivirea are loc la indexul indicat de proprietatea lastIndex a acestei expresii regulate, în timp ce potrivirea nu este efectuată la un index ulterior sau anterior ( steag lipicios).

Seturi de caractere

Metacaracterele

SimbolDescriere
. Vă permite să găsiți un singur caracter, altul decât un caracter nou sau de final de linie (\n, \r, \u2028 sau \u2029).
\dVă permite să găsiți un simbol numeric în alfabetul latin de bază. Echivalent cu utilizarea setului de caractere.
\DVă permite să găsiți orice caracter care nu este un număr în alfabetul latin de bază. Echivalent cu setul de caractere [^0-9].
\sVă permite să găsiți un singur caracter de spațiu alb. Spațiul alb se referă la spațiu, tabulator, flux de pagină, avans de linie și alte caractere de spațiu alb Unicode. Echivalent cu setul de caractere [\f\n\r\t\v​\u00a0\u1680​\u180e\u2000​\u2001\u2002​\u2003\u2004\u2005\u2006\u2007\u20008\u2008\ u200a​ \u2028\u2029​\u202f\u205f​\u3000].
\SVă permite să găsiți un singur caracter care nu este spațiu alb. Spațiul alb se referă la spațiu, tab, flux de pagină, avans de linie și alte caractere de spațiu alb Unicode. Echivalent cu setul de caractere [^ \f\n\r\t\v​\u00a0\u1680​\u180e\u2000​\u2001\u2002​\u2003\u2004\u2005\u2006\u2007\u2008 \u200a ​\u2028\u2029​\u202f\u205f​\u3000].
[\b]Vă permite să găsiți caracterul backspace (caracterul special \b, U+0008).
\0 Vă permite să găsiți simbolul 0 (zero).
\nVă permite să găsiți caracterul newline.
\fVă permite să găsiți caracterul de feed al paginii.
\rVă permite să găsiți caracterul de întoarcere a căruciorului.
\tVă permite să găsiți caracterul de filă orizontală.
\vVă permite să găsiți caracterul de filă verticală.
\wVă permite să găsiți orice caracter alfanumeric în alfabetul latin de bază, inclusiv caractere de subliniere. Echivalent cu setul de caractere.
\WVă permite să găsiți orice caracter care nu este un caracter din alfabetul latin de bază. Echivalent cu setul de caractere [^a-Za-z0-9_].
\cXVă permite să găsiți un caracter de control într-un șir. Unde X este litera de la A la Z. De exemplu, /\cM/ reprezintă caracterul Ctrl-M.
\xhhVă permite să găsiți un caracter folosind o valoare hexazecimală (hh este o valoare hexazecimală de două cifre).
\uhhhhVă permite să găsiți un caracter utilizând codificarea UTF-16 (hhhh este o valoare hexazecimală de patru cifre).
\u(hhhh) sau
\u(hhhhh)
Vă permite să găsiți un caracter cu o valoare Unicode de U+hhhh sau U+hhhhh (valoare hexazecimală). Numai când este dat steagul u.
\ Indică faptul că următorul caracter este special și nu trebuie interpretat literal. Pentru caracterele care sunt de obicei interpretate într-un mod special, specifică faptul că următorul caracter nu este special și trebuie interpretat literal.

Restricții

Cuantificatori

SimbolDescriere
n*Potrivirea are loc pe orice șir care conține zero sau mai multe apariții ale caracterului n.
n+Potrivirea are loc cu orice șir care conține cel puțin un caracter n.
n?Potrivirea are loc pe orice șir cu un element precedent n zero sau o dată.
n(x)Se potrivește cu orice șir care conține o secvență de caractere n un anumit număr de ori X. X
n(x,) X aparițiile elementului precedent n. X trebuie să fie un număr întreg pozitiv.
n(x, y)Se potrivește cu orice șir care conține cel puțin X, dar nu mai mult decât cu y aparițiile elementului precedent n. XȘi y trebuie să fie numere întregi pozitive.
n*?
n+?
n??
n(x)?
n(x,)?
n(x,y)?
Comparația are loc prin analogie cu cuantificatorii *, +, ? și (...), însă în același timp căutarea este în curs comparația minimă posibilă. Implicit este modul „lacom”, ? la sfârșitul cuantificatorului vă permite să setați un mod „non-lacom” în care comparația este repetată de un număr minim posibil de ori.
x(?=y)Vă permite să comparați X, numai dacă pentru X ar trebui să y.
X y)Vă permite să comparați X, numai dacă pentru X nu o face y.
x|yComparația are loc cu oricare dintre alternativele specificate.

Grupare și backlink

SimbolDescriere
(X)Vă permite să găsiți un simbol Xși amintiți-vă rezultatul comparației („capturarea parantezelor”). Subșirul potrivit poate fi apelat din elementele matricei rezultate ..., [n] sau din proprietățile obiectului RegExp predefinit $1 ..., $9.
(?:X)Vă permite să găsiți un simbol X, dar nu își amintește rezultatul meciului („paranteze fără captură”). Subșirul potrivit nu poate fi apelat din elementele matricei rezultate ..., [n] sau din proprietățile obiectului RegExp predefinit $1 ..., $9.
\nO referință returnată la ultimul subșir care se potrivește cu al n-a dintre paranteze într-o expresie regulată (numerotarea parantezelor merge de la stânga la dreapta). n trebuie să fie un număr întreg pozitiv.

Unii oameni, când se confruntă cu o problemă, gândesc: „Oh, voi folosi expresii obișnuite”. Acum au două probleme.
Jamie Zawinski

Yuan-Ma a spus: „Este nevoie de multă forță pentru a tăia lemnul peste granulația lemnului. Este nevoie de mult cod pentru a programa în structura problemei.
Maestrul Yuan-Ma, „Cartea programării”

Instrumentele și tehnicile de programare supraviețuiesc și se răspândesc într-o manieră evolutivă haotică. Uneori nu cei frumoși și străluciți supraviețuiesc, ci pur și simplu cei care funcționează suficient de bine în domeniul lor - de exemplu, dacă sunt integrati într-o altă tehnologie de succes.

În acest capitol, vom discuta despre un astfel de instrument - expresiile regulate. Acesta este un mod de a descrie modele în date șir. Ei creează un limbaj mic, de sine stătător, care este inclus în JavaScript și în multe alte limbi și instrumente.

Programele regulate sunt atât foarte ciudate, cât și extrem de utile. Sintaxa lor este criptică și interfata software JavaScript este incomod pentru ei. Dar este un instrument puternic pentru explorarea și manipularea șirurilor. Odată ce le înțelegi, vei deveni un programator mai eficient.

Crearea unei expresii regulate

Regular – tip de obiect. Poate fi creat apelând constructorul RegExp sau prin scriere șablonul necesar, înconjurat de tăieturi.

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

Ambele expresii regulate reprezintă același model: caracterul „a” urmat de caracterul „b” urmat de caracterul „c”.

Dacă utilizați constructorul RegExp, modelul este scris ca sfoară obișnuită, deci se aplică toate regulile privind barele oblice inverse.

A doua intrare, unde modelul este între bare oblice, tratează diferit barele oblice inverse. În primul rând, deoarece modelul se termină cu o oblică înainte, trebuie să punem o bară oblică inversă înaintea barei oblice pe care dorim să o includem în modelul nostru. În plus, barele oblice inverse care nu fac parte din caractere speciale precum \n vor fi păstrate (mai degrabă decât ignorate ca în șiruri de caractere) și vor schimba semnificația modelului. Unele caractere, cum ar fi semnul de întrebare sau plus, au o semnificație specială în expresiile obișnuite și, dacă trebuie să potriviți un astfel de caracter, acesta trebuie să fie precedat și de o bară oblică inversă.

Var eighteenPlus = /eighteen\+/;

Pentru a ști ce caractere trebuie să fie precedate de o bară oblică, trebuie să înveți o listă cu toate caracterele speciale din expresiile regulate. Acest lucru nu este încă posibil, așa că atunci când aveți îndoieli, puneți o bară oblică inversă în fața oricărui caracter care nu este o literă, un număr sau un spațiu.

Se verifică potriviri

Obisnuitii au mai multe metode. Cel mai simplu este testul. Dacă îi treceți un șir, acesta va returna o valoare booleană care indică dacă șirul conține o apariție a modelului dat.

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

O secvență obișnuită constând numai din caractere nespeciale este pur și simplu o secvență a acestor caractere. Dacă abc este oriunde în linia pe care o testăm (nu doar la început), testul va returna true.

Caut un set de personaje

De asemenea, puteți afla dacă un șir conține abc folosind indexOf. Modelele obișnuite vă permit să mergeți mai departe și să creați modele mai complexe.

Să presupunem că trebuie să găsim orice număr. Când punem un set de caractere între paranteze drepte în expresia regulată, înseamnă că acea parte a expresiei se potrivește cu oricare dintre caracterele dintre paranteze.

Ambele expresii sunt în linii care conțin un număr.

Console.log(//.test(„în 1992”)); // → adevărat console.log(//.test(„în 1992”)); // → adevărat

Între paranteze drepte, o liniuță între două caractere este utilizată pentru a specifica intervalul de caractere în care este specificată secvența Codificare Unicode. Caracterele de la 0 la 9 sunt acolo doar pe rând (coduri de la 48 la 57), așa că le captează pe toate și se potrivește cu orice număr.

Mai multe grupuri de caractere au propriile lor abrevieri încorporate.

\d Orice număr
\w Caracter alfanumeric
\s caracter de spațiu alb (spațiu, tabulator, linie nouă etc.)
\D nu un număr
\W nu este un caracter alfanumeric
\S nu este un caracter alb
. orice caracter, cu excepția avansului de linie

Astfel, puteți seta formatul de dată și oră ca 30/01/2003 15:20 cu următoarea expresie:

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")); // → fals

Arată groaznic, nu-i așa? Există prea multe bare oblice inverse, ceea ce face modelul dificil de înțeles. Îl vom îmbunătăți puțin mai târziu.

Barele oblice inverse pot fi folosite și între paranteze drepte. De exemplu, [\d.] înseamnă orice număr sau punct. Observați că perioada din paranteze pătrate își pierde semnificația specială și devine pur și simplu o perioadă. Același lucru este valabil și pentru alte caractere speciale, cum ar fi +.

Puteți inversa un set de caractere - adică să spunem că trebuie să găsiți orice caracter, cu excepția celor care sunt în set - prin plasarea unui semn ^ imediat după paranteza pătrată de deschidere.

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

Repetarea părților șablonului

Știm cum să găsim un număr. Ce se întâmplă dacă trebuie să găsim întregul număr - o secvență de una sau mai multe cifre?

Dacă puneți semnul + după ceva în secvența obișnuită, aceasta va însemna că acest element poate fi repetat de mai multe ori. /\d+/ înseamnă una sau mai multe cifre.

Console.log(/"\d+"/.test(""123"")); // → adevărat console.log(/"\d+"/.test("""")); // → false console.log(/"\d*"/.test(""123"")); // → adevărat console.log(/"\d*"/.test("""")); // → adevărat

Asteriscul * are aproape aceeași semnificație, dar permite ca modelul să apară de zero ori. Dacă ceva este urmat de un asterisc, atunci nu împiedică niciodată modelul să fie în linie - apare doar acolo de zero ori.

Un semn de întrebare face ca o parte a modelului să fie opțională, ceea ce înseamnă că poate apărea zero sau o dată. În exemplul următor, poate apărea caracterul u, dar modelul se potrivește chiar și atunci când nu apare.

Var vecin = /neighbou?r/; console.log(vecin.test(„vecin”); // → adevărat console.log(vecin.test(„vecin”); // → adevărat

Acoladele sunt folosite pentru a specifica de câte ori trebuie să apară un model. (4) după un element înseamnă că trebuie să apară de 4 ori în linie. De asemenea, puteți specifica un interval: (2,4) înseamnă că elementul trebuie să apară de cel puțin 2 și nu mai mult de 4 ori.

O altă versiune a formatului de dată și oră, în care zilele, lunile și orele de una sau două cifre sunt permise. Și este, de asemenea, puțin mai lizibil.

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

Puteți folosi spații deschise omițând unul dintre numere. (,5,) înseamnă că modelul poate apărea de la zero la cinci ori, iar (5,) înseamnă de la cinci sau mai multe.

Gruparea subexpresiilor

Pentru a utiliza operatorii * sau + pe mai multe elemente simultan, puteți utiliza paranteze rotunde. Partea expresiei regulate cuprinsă între paranteze este considerată un element din punctul de vedere al operatorilor.

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

Primul și al doilea plus se aplică numai celui de-al doilea O din boo și hoo. Al treilea + se referă la întregul grup (hoo+), găsind una sau mai multe astfel de secvențe.

Litera i de la sfârșitul expresiei face ca expresia regulată să nu țină seama de majuscule și minuscule - astfel încât B se potrivește cu b.

Meciuri și grupe

Metoda de testare este cea mai simplă metodă de verificare a expresiilor regulate. Vă spune doar dacă o potrivire a fost găsită sau nu. Obișnuiții au, de asemenea, o metodă exec, care va returna null dacă nu a fost găsit nimic și, în caz contrar, va returna un obiect cu informații despre potrivire.

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

Obiectul returnat de exec are proprietatea indexului, care conține numărul caracterului de la care a avut loc potrivirea. În general, obiectul arată ca o matrice de șiruri, unde primul element este șirul care a fost verificat pentru o potrivire. În exemplul nostru, aceasta va fi succesiunea de numere pe care o căutam.

Șirurile au o metodă de potrivire care funcționează în același mod.

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

Când o expresie obișnuită conține subexpresii grupate prin paranteze, textul care se potrivește cu aceste grupuri va apărea de asemenea în matrice. Primul element este întotdeauna o potrivire completă. A doua este partea care s-a potrivit cu primul grup (cel ale cărui paranteze au apărut mai întâi), apoi al doilea grup și așa mai departe.

Var quotedText = /"([^"]*)"/; console.log(quotedText.exec ("ea a spus "bună"")); // → [""bună ziua", "bună ziua"]

Când un grup nu este găsit deloc (de exemplu, dacă este urmat de un semn de întrebare), poziția sa în matrice este nedefinită. Dacă un grup se potrivește de mai multe ori, atunci numai ultimul meci va fi în matrice.

Console.log(/bad(ly)?/.exec(„rea”); // → [„prost”, nedefinit] console.log(/(\d)+/.exec(„123”)); // → ["123", "3"]

Grupurile sunt utile pentru a prelua părți de șiruri. Dacă nu vrem doar să verificăm dacă un șir are o dată, ci să îl extragem și să creăm un obiect reprezentând data, putem include secvențele de numere în paranteze și selectam data din rezultatul exec.

Dar mai întâi, o mică digresiune în care vom afla modul preferat de a stoca data și ora în JavaScript.

Tipul de dată

JavaScript are un tip de obiect standard pentru date – mai precis, momente în timp. Se numește Data. Dacă pur și simplu creați un obiect data prin new, veți obține data curenta si timpul.

Console.log(data noua()); // → Duminica 09 noiembrie 2014 00:07:57 GMT+0300 (CET)

De asemenea, puteți crea un obiect care conține un anumit timp

Console.log(new Date(2015, 9, 21)); // → Miercuri 21 octombrie 2015 00:00:00 GMT+0300 (CET) console.log(new Date(2009, 11, 9, 12, 59, 59, 999)); // → miercuri 09 decembrie 2009 12:59:59 GMT+0300 (CET)

JavaScript folosește o convenție în care numerele lunii încep cu zero și numerele zilei cu unu. Acest lucru este stupid și ridicol. Atenție.

Ultimele patru argumente (ore, minute, secunde și milisecunde) sunt opționale și sunt setate la zero dacă lipsesc.

Marcajele de timp sunt stocate ca număr de milisecunde care au trecut de la începutul anului 1970. Pentru perioadele dinainte de 1970, folosiți numere negative(acest lucru se datorează convenției de timp Unix care a fost creată în acea perioadă). Metoda getTime a obiectului data returnează acest număr. Este în mod natural mare.
console.log(new Date(2013, 11, 19).getTime()); // → 1387407600000 console.log(new Date(1387407600000)); // → Joi, 19 decembrie 2013 00:00:00 GMT+0100 (CET)

Dacă dați constructorului Date un argument, acesta este tratat ca acest număr de milisecunde. Puteți obține valoarea curentă în milisecunde creând un obiect Date și apelând metoda getTime sau apelând funcția Date.now.

Obiectul Date are metode getFullYear, getMonth, getDate, getHours, getMinutes și getSeconds pentru a prelua componentele sale. Există, de asemenea, o metodă getYear care returnează un cod de două cifre destul de inutil, cum ar fi 93 sau 14.

Prin includerea părților relevante ale șablonului în paranteze, putem crea un obiect dată direct din șir.

Funcția findDate(șir) ( var dateTime = /(\d(1,2))-(\d(1,2))-(\d(4))/; var potrivire = dateTime.exec(șir); return new Date(Număr(potrivire), Număr(potrivire) - 1, Număr(potrivire) ) console.log(findDate("30-1-2003")); // → Joi, 30 ianuarie 2003 00:00:00 GMT+0100 (CET)

Limite de cuvinte și linii

Din păcate, findDate va extrage la fel de fericit și data fără sens 00-1-3000 din șirul „100-1-30000”. Potrivirea poate avea loc oriunde în șir, deci în acest caz, pur și simplu va începe de la al doilea caracter și se va termina pe al doilea caracter.

Dacă trebuie să forțăm potrivirea să preia întregul șir, folosim etichetele ^ și $. ^ se potrivește cu începutul liniei, iar $ se potrivește cu sfârșitul. Prin urmare, /^\d+$/ se potrivește unui șir format din doar una sau mai multe cifre, /^!/ se potrivește unui șir care începe cu semn de exclamareși /x^/ nu se potrivește cu nicio linie (nu poate exista un x înainte de începutul liniei).

Dacă, pe de altă parte, vrem doar să ne asigurăm că data începe și se termină la granița unui cuvânt, folosim semnul \b. O limită a unui cuvânt poate fi începutul sau sfârșitul unei linii sau orice loc dintr-o linie unde există un caracter alfanumeric \w pe o parte și un caracter nealfanumeric pe cealaltă parte.

Console.log(/cat/.test(„concatenate”)); // → true console.log(/\bcat\b/.test(„concatenate”)); // → fals

Rețineți că eticheta de delimitare nu este un simbol. Este pur și simplu o constrângere, ceea ce înseamnă că o potrivire are loc numai dacă este îndeplinită o anumită condiție.

Șabloane cu alegere

Să presupunem că trebuie să aflați dacă textul conține nu doar un număr, ci un număr urmat de porc, vaca sau pui la singular sau plural.

Ar fi posibil să scrieți trei expresii regulate și să le verificați una câte una, dar există o modalitate mai bună. Simbol | denotă o alegere între modelele din stânga și din dreapta acestuia. Și putem spune următoarele:

Var animalCount = /\b\d+ (porc|vacă|pui)s?\b/; console.log(animalCount.test("15 porci"); // → true console.log(animalCount.test("15 pui de porc")); // → fals

Parantezele delimitează porțiunea modelului la care se aplică | și mulți astfel de operatori pot fi plasați unul după altul pentru a indica o alegere dintre mai mult de două opțiuni.

Motor de căutare

Expresii obisnuite pot fi privite ca organigrame. Următoarea diagramă descrie un exemplu recent de animale.

O expresie se potrivește cu un șir dacă este posibil să găsiți o cale din partea stângă a diagramei la dreapta. Ne amintim poziția curentă în linie și de fiecare dată când trecem prin dreptunghi, verificăm dacă partea de linie imediat după poziția noastră în ea se potrivește cu conținutul dreptunghiului.

Aceasta înseamnă că verificarea dacă caracterul nostru obișnuit se potrivește cu șirul „cei 3 porci” atunci când parcurgeți diagrama de flux arată astfel:

La poziția 4 există o limită de cuvânt și trecem de primul dreptunghi
- incepand din pozitia a 4-a gasim numarul si trecem prin al doilea dreptunghi
- la poziția 5, o cale se închide înapoi în fața celui de-al doilea dreptunghi, iar a doua merge mai departe către dreptunghi cu un spațiu. Avem un spațiu, nu un număr și alegem a doua cale.
- acum suntem pe pozitia 6, inceputul “porcilor”, si la tripla ramificare a potecilor. Nu există „vacă” sau „pui” în linie, dar există „porc”, așa că alegem această cale.
- în poziția 9 după bifurcația triplă, o cale ocolește „s” și merge la ultimul dreptunghi de limită a cuvântului, iar a doua trece prin „s”. Avem un „s”, așa că mergem acolo.
- la poziția 10 suntem la sfârșitul liniei și doar limita cuvântului se poate potrivi. Capătul liniei este considerat graniță și trecem prin ultimul dreptunghi. Și acum am găsit cu succes șablonul nostru.

Practic, modul în care funcționează expresiile regulate este că algoritmul începe la începutul șirului și încearcă să găsească o potrivire acolo. În cazul nostru, există o limită a cuvântului, deci trece de primul dreptunghi - dar nu există niciun număr acolo, așa că se împiedică de al doilea dreptunghi. Apoi trece la al doilea caracter din șir și încearcă să găsească o potrivire acolo... Și așa mai departe până când găsește o potrivire sau ajunge la sfârșitul șirului, caz în care nu se găsește nicio potrivire.

Kickback-uri

Expresia regulată /\b(+b|\d+|[\da-f]h)\b/ se potrivește fie cu un număr binar urmat de un b, cu un număr zecimal fără sufix, fie cu un număr hexazecimal (numerele de la 0 la 9 sau simbolurile de la a la h), urmate de h. Diagrama relevanta:

Când căutați o potrivire, se poate întâmpla ca algoritmul să ia calea de sus (număr binar), chiar dacă nu există un astfel de număr în șir. Dacă există o linie „103”, de exemplu, este clar că numai după ce ajunge la numărul 3 algoritmul va înțelege că este pe calea greșită. În general, linia se potrivește cu secvența obișnuită, doar că nu în acest fir.

Apoi algoritmul revine. La o bifurcație, își amintește poziția curentă (în cazul nostru, acesta este începutul liniei, imediat după limita cuvântului), astfel încât să puteți întoarce înapoi și să încercați o altă cale dacă cea aleasă nu funcționează. Pentru linia „103”, după ce a întâlnit troica, se va întoarce și va încerca să treacă prin calea pentru numere zecimale. Acest lucru va funcționa, astfel încât o potrivire va fi găsită.

Algoritmul se oprește imediat ce găsește o potrivire completă. Aceasta înseamnă că, chiar dacă mai multe opțiuni pot fi potrivite, se folosește doar una dintre ele (în ordinea în care apar în secvența obișnuită).

Backtracking apare atunci când se utilizează operatori de repetiție precum + și *. Dacă căutați /^.*x/ în șirul „abcxe”, partea regex.* va încerca să consume întregul șir. Algoritmul va realiza apoi că are nevoie și de „x”. Deoarece nu există niciun „x” după sfârșitul șirului, algoritmul va încerca să caute o potrivire deplasând înapoi cu un caracter. După abcx nu există nici un x, apoi se întoarce din nou, de data aceasta la subșirul abc. Iar după linie, găsește x și raportează o potrivire reușită, în pozițiile de la 0 la 4.

Puteți scrie o rutină obișnuită care va duce la mai multe derulări. Această problemă apare atunci când modelul poate potrivi datele de intrare de mai multe ori. căi diferite. De exemplu, dacă facem o greșeală când scriem o expresie regulată for numere binare, am putea scrie accidental ceva de genul /(+)+b/.

Dacă algoritmul caută un astfel de model în linie lunga de zerouri și cele care nu conține un „b” la sfârșit, va trece mai întâi prin bucla interioară până când rămâne fără cifre. Apoi va observa că nu există un „b” la sfârșit, va întoarce o poziție înapoi, va trece prin bucla exterioară, va renunța din nou, va încerca să se rotească înapoi într-o altă poziție de-a lungul buclei interioare... Și va continua pentru a căuta în acest fel, folosind ambele bucle. Adică, cantitatea de lucru cu fiecare caracter al liniei se va dubla. Chiar și pentru câteva zeci de personaje, găsirea unei potriviri va dura foarte mult timp.

metoda înlocuirii

Șirurile au o metodă de înlocuire care poate înlocui o parte dintr-un șir cu un alt șir.

Console.log("tata".replace("p", "m")); // → hartă

Primul argument poate fi și o expresie regulată, caz în care prima apariție a expresiei regulate din linie este înlocuită. Când opțiunea „g” (globală) este adăugată la o expresie regulată, toate aparițiile sunt înlocuite, nu doar prima

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

Ar fi logic să treceți opțiunea „înlocuiți tot” printr-un argument separat sau printr-o metodă separată, cum ar fi replaceAll. Dar, din păcate, opțiunea este transmisă prin sistemul obișnuit în sine.

Puterea deplină a expresiilor regulate este dezvăluită atunci când folosim link-uri către grupuri găsite într-un șir, specificate în expresia regulată. De exemplu, avem o linie care conține numele persoanelor, câte un nume pe rând, în formatul „Nume, prenume”. Dacă trebuie să le schimbăm și să eliminăm virgula pentru a obține „Nume de familie”, scriem următoarele:

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

$1 și $2 în linia de înlocuire se referă la grupuri de caractere cuprinse între paranteze. $1 este înlocuit cu textul care se potrivește cu primul grup, $2 cu al doilea grup și așa mai departe, până la $9. Întreaga potrivire este conținută în variabila $&.

De asemenea, puteți trece o funcție ca al doilea argument. Pentru fiecare înlocuire, va fi apelată o funcție ale cărei argumente vor fi grupurile găsite (și toată partea corespunzătoare a liniei), iar rezultatul acesteia va fi inserat într-o nouă linie.

Exemplu simplu:

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

Iată una mai interesantă:

Stock de var = „1 lămâie, 2 varză și 101 ouă”; funcția minusOne(potrivire, cantitate, unitate) ( cantitate = Număr (cantitate) - 1; dacă (cantitate == 1) // a rămas doar unul, eliminați „s” de la sfârșit unit = unit.slice(0, unit. lungime - 1; else if (cantitate == 0) suma = "nu" + unitate) console.log(stock.replace(/(\d+)/g, minusOne); ); // → fără lămâie, 1 varză și 100 de ouă

Codul ia un șir, găsește toate aparițiile numerelor urmate de un cuvânt și returnează un șir cu fiecare număr redus cu unul.

Grupul (\d+) intră în argumentul cantitate, iar (\w+) intră în argumentul unitate. Funcția convertește suma într-un număr - și aceasta funcționează întotdeauna, deoarece modelul nostru este \d+. Și apoi face modificări la cuvânt, în cazul în care rămâne doar 1 articol.

Lăcomie

Este ușor de utilizat înlocuire pentru a scrie o funcție care elimină toate comentariile din Cod JavaScript. Iată prima încercare:

Funcția stripComments(cod) ( return code.replace(/\/\/.*|\/\*[^]*\*\//g, ""); ) console.log(stripComments("1 + /* 2 */3")); // → 1 + 3 console.log(stripComments("x = 10;// zece!")); // → x = 10; console.log(stripComments("1 /* a */+/* b */ 1")); // → 1 1

Partea dinaintea operatorului „sau” se potrivește cu două bare oblice urmate de orice număr de caractere, cu excepția liniilor noi. Partea care elimină comentariile pe mai multe rânduri este mai complexă. Folosim [^], i.e. orice caracter care nu este gol ca o modalitate de a găsi orice personaj. Nu putem folosi un punct deoarece blocarea comentariilor continuă linie nouă, iar caracterul newline nu se potrivește cu punctul.

Dar rezultatul exemplului anterior este incorect. De ce?

Partea [^]* va încerca mai întâi să capteze cât mai multe personaje. Dacă din această cauză următoarea parte a secvenței obișnuite nu găsește o potrivire, va derula un caracter înapoi și va încerca din nou. În exemplu, algoritmul încearcă să prindă întreaga linie, apoi se derulează înapoi. După ce a derulat înapoi 4 caractere, el va găsi */ în linie - și nu este ceea ce ne-am dorit. Am vrut să luăm un singur comentariu, și nu să mergem la sfârșitul rândului și să găsim ultimul comentariu.

Din această cauză, spunem că operatorii de repetiție (+, *, ? și ()) sunt lacomi, adică mai întâi apucă cât pot și apoi se întorc. Dacă puneți o întrebare după un astfel de operator (+?, *?, ??, ()?), ei se vor transforma în non-lacomi și vor începe să găsească cele mai mici apariții posibile.

Și de asta avem nevoie. Forțând asteriscul să găsească potriviri în numărul minim posibil de caractere dintr-o linie, consumăm doar un bloc de comentarii și nu mai mult.

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

Multe erori apar atunci când se folosesc operatori lacomi în loc de cei care nu sunt lacomi. Când utilizați operatorul de repetare, luați în considerare întotdeauna mai întâi operatorul non-lacom.

Crearea dinamică a obiectelor RegExp

În unele cazuri, modelul exact nu este cunoscut în momentul în care este scris codul. De exemplu, va trebui să căutați numele utilizatorului în text și să-l încadrați în litere de subliniere. Deoarece veți ști numele numai după rularea programului, nu puteți utiliza notația oblică.

Dar puteți construi șirul și utilizați constructorul RegExp. Iată un exemplu:

Var nume = „harry”; var text = „Și Harry are o cicatrice pe frunte.”; var regexp = new RegExp("\\b(" + nume + ")\\b", "gi"); console.log(text.replace(regexp, "_$1_")); // → Și _Harry_ are o cicatrice pe frunte.

Când creăm limite de cuvinte, trebuie să folosim bare oblice duble, deoarece le scriem într-o linie normală, și nu într-o secvență obișnuită cu bare oblice înainte. Al doilea argument la RegExp conține opțiuni pentru expresii regulate - în cazul nostru „gi”, adică. globală și insensibilă la majuscule și minuscule.

Dar dacă numele este „dea+hlrd” (dacă utilizatorul nostru este un kulhatzker)? Ca rezultat, vom obține o expresie regulată fără sens care nu va găsi potriviri în șir.

Putem adăuga bare oblice inverse înaintea oricărui personaj care nu ne place. Nu putem adăuga bare oblice inverse înainte de litere deoarece \b sau \n sunt caractere speciale. Dar puteți adăuga bare oblice înaintea oricăror caractere non-alfanumerice fără probleme.

Var name = "dea+hlrd"; var text = "Acest dea+hlrd enervează pe toată lumea."; var escape = name.replace(/[^\w\s]/g, "\\$&"); var regexp = new RegExp("\\b(" + escape + ")\\b", "gi"); console.log(text.replace(regexp, "_$1_")); // → Această _dea+hlrd_ a enervat pe toată lumea.

metoda de cautare

Metoda indexOf nu poate fi utilizată cu expresii regulate. Dar există o metodă de căutare care așteaptă doar expresia regulată. La fel ca indexOf, returnează indexul primei apariții sau -1 dacă nu apare niciuna.

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

Din păcate, nu există nicio modalitate de a spune metodei să caute o potrivire începând cu un anumit offset (cum poți face cu indexOf). Asta ar fi de ajutor.

proprietate lastIndex

Nici metoda exec nu funcționează mod convenabilîncepeți căutarea dintr-o poziție dată în șir. Dar oferă un mod incomod.

Un obiect regex are proprietăți. Una dintre ele este sursa, care conține un șir. Un altul este lastIndex, care controlează, în anumite condiții, unde va începe următoarea căutare a aparițiilor.

Aceste condiții includ faptul că opțiunea globală g trebuie să fie prezentă și că căutarea trebuie efectuată folosind metoda exec. O soluție mai rezonabilă ar fi să permiteți pur și simplu să se transmită un argument suplimentar către exec, dar caracterul rezonabil nu este o caracteristică fundamentală a interfeței JavaScript regex.

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

Dacă căutarea a avut succes, apelul exec actualizează proprietatea lastIndex pentru a indica poziția după apariția găsită. Dacă nu a avut succes, lastIndex este setat la zero - la fel ca lastIndex al obiectului nou creat.

Când utilizați o variabilă obișnuită globală și apeluri mai multe exec, acestea actualizari automate lastIndex poate cauza probleme. Serviciul dumneavoastră obișnuit poate începe căutarea din poziția rămasă de la apelul anterior.

Var digit = /\d/g; console.log(digit.exec("aici este: 1")); // → ["1"] console.log(digit.exec("și acum: 1")); // → nul

O alta efect interesant Opțiunea g este că schimbă modul în care funcționează metoda de potrivire. Când este apelat cu această opțiune, în loc să returneze o matrice similară cu rezultatul exec, găsește toate aparițiile modelului din șir și returnează o matrice a subșirurilor găsite.

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

Așa că aveți grijă cu variabilele globale regulate. Cazurile în care sunt necesare - înlocuiți apelurile sau locurile în care utilizați în mod specific lastIndex - sunt probabil toate cazurile în care ar trebui să fie utilizate.

Cicluri de apariție

O sarcină tipică este să iterați prin toate aparițiile unui model dintr-un șir, astfel încât să poată accesa obiectul potrivire din corpul buclei, folosind lastIndex și exec.

Var input = "O linie cu 3 numere în ea... 42 și 88."; număr var = /\b(\d+)\b/g; var potrivire; while (potrivire = număr.exec(intrare)) console.log(„Găsit”, potrivire, „pe”, potrivire.index); // → Găsit 3 la 14 // Găsit 42 la 33 // Găsit 88 la 40

Se profită de faptul că valoarea atribuirii este valoarea atribuită. Folosind match = re.exec(input) ca o condiție în buclă while, căutăm la începutul fiecărei iterații, stocăm rezultatul într-o variabilă și încheiem bucla când sunt găsite toate potrivirile.

Analizarea fișierelor INI

Pentru a încheia capitolul, să ne uităm la o problemă folosind expresii regulate. Imaginați-vă că scriem un program care colectează automat informații despre inamicii noștri prin Internet. (Nu vom scrie întregul program, ci doar partea care citește fișierul de setări. Ne pare rău.) Fișierul arată astfel:

Searchengine=http://www.google.com/search?q=$1 spitefulness=9.7 ; se pune punct și virgulă înaintea comentariilor; fiecare secțiune se referă la un inamic diferit nume complet=Larry Doe tip=website taur grădiniță=http://www.geocities.com/CapeCanaveral/11451 fullname=Gargamel tip=vrăjitor rău outputdir=/home/marijn/enemies/gargamel

Formatul exact de fișier (care este destul de utilizat pe scară largă și se numește de obicei INI) este următorul:

Liniile goale și liniile care încep cu punct și virgulă sunt ignorate
- liniile cuprinse între paranteze drepte încep o nouă secțiune
- linii care conțin un identificator alfanumeric urmat de = adăugați o setare în această secțiune

Toate celelalte sunt date incorecte.

Sarcina noastră este să convertim un astfel de șir într-o matrice de obiecte, fiecare cu o proprietate de nume și o matrice de setări. Este necesar un obiect pentru fiecare secțiune, iar altul este necesar pentru setările globale din partea de sus a fișierului.

Deoarece fișierul trebuie analizat linie cu linie, este o idee bună să începeți prin a împărți fișierul în linii. Pentru a face acest lucru, am folosit string.split("\n") în Capitolul 6. Unele sisteme de operare folosesc nu un caracter \n pentru întreruperi de linie, ci două - \r\n. Deoarece metoda split ia expresii regulate ca argument, putem împărți linii folosind expresia /\r?\n/, permițând atât \n cât și \r\n între linii.

Funcția parseINI(șir) ( // Să începem cu un obiect care conține setări nivel superior var currentSection = (nume: null, câmpuri: ); var categorii = ; string.split(/\r?\n/).forEach(function(line) ( var potrivire; if (/^\s*(;.*)?$/.test(line)) ( return; ) else if (potrivire = line.match(/^\[(.*)\]$/)) ( currentSection = (nume: potrivire, câmpuri: ); categories.push(currentSection); ) else if (potrivire = line.match( /^(\w+)=(.*)$/)) ( currentSection.fields.push((nume: potrivire, valoare: potrivire)); ) else ( throw new Error ("Linia "" + linia + "" conține date greșite."); ) )); categorii de returnare; )

Codul parcurge toate liniile, actualizând obiectul secțiunii curente „secțiunea curentă”. În primul rând, verifică dacă linia poate fi ignorată folosind expresia regulată /^\s*(;.*)?$/. Vă puteți imagina cum funcționează asta? Partea dintre paranteze se potrivește cu comentariile, nu? face astfel încât caracterul obișnuit să se potrivească, de asemenea, linii formate doar din spații.

Dacă linia nu este un comentariu, codul verifică dacă începe o nouă secțiune. Dacă da, creează un nou obiect pentru secțiunea curentă, la care se adaugă setările ulterioare.

Ultima posibilitate semnificativă este că șirul este setare normală, caz în care se adaugă obiectului curent.

Dacă niciuna dintre opțiuni nu funcționează, funcția afișează o eroare.

Observați cum utilizare frecventă^ și $ asigură-te că expresia se potrivește întregului șir, nu doar unei părți a acestuia. Dacă nu le folosiți, codul va funcționa în general, dar uneori va arunca rezultate ciudate, iar o astfel de eroare va fi dificil de găsit.

Construcția if (match = string.match(...)) este similară cu trucul de a folosi atribuirea ca condiție într-o buclă while. Adesea nu știi că apelul de potrivire va reuși, așa că poți accesa doar obiectul rezultat în interiorul unui bloc if care îl verifică. Pentru a nu rupe lanțul frumos al verificărilor if, atribuim rezultatul căutării unei variabile și folosim imediat această atribuire ca verificare.

Simboluri internaționale

Datorită implementării inițial simple a limbajului și fixării ulterioare a unei astfel de implementări „în granit”, expresiile regulate JavaScript sunt stupide cu caractere care nu se găsesc în limba engleză. De exemplu, caracterul „litera”, din punctul de vedere al expresiilor regulate JavaScript, poate fi una dintre cele 26 de litere ale alfabetului englez și, din anumite motive, și un caracter de subliniere. Litere precum é sau β, care sunt în mod clar litere, nu se potrivesc cu \w (și se vor potrivi cu \W, care este o non-litera).

Într-o coincidență ciudată, istoricul \s (spațiu) se potrivește cu toate caracterele care sunt considerate spații albe în Unicode, inclusiv lucruri precum spatiu de nerupere sau separator de vocale mongole.

Unele implementări regex în alte limbi au sintaxă specială pentru căutarea categoriilor speciale de caractere Unicode, cum ar fi „toate litere mari”, „toate semnele de punctuație” sau „caracterele de control”. Există planuri de a adăuga astfel de categorii la JavaScript, dar ele, aparent, nu vor fi implementate în curând.

Concluzie

Regularii sunt obiecte care reprezintă modele de căutare în șiruri. Ei folosesc propria sintaxă pentru a exprima aceste modele.

/abc/ Secvență de caractere
// Orice caracter din listă
/[^abc]/ Orice caracter, cu excepția caracterelor din listă
// Orice caracter din interval
/x+/ Una sau mai multe apariții ale modelului x
/x+?/ Una sau mai multe apariții, nelacom
/x*/ Zero sau mai multe apariții
/x?/ Zero sau o apariție
/x(2,4)/ De la două până la patru apariții
/(abc)/ Grup
/a|b|c/ Oricare dintre mai multe modele
/\d/ Orice număr
/\w/ Orice caracter alfanumeric („litera”)
/\s/ Orice caracter alb
/./ Orice caracter, cu excepția întreruperilor de rând
/\b/ Limita cuvântului
/^/ Începutul liniei
/$/ Sfârșitul rândului

Regex are o metodă de testare pentru a verifica dacă modelul este în șir. Există o metodă exec care returnează o matrice care conține toate grupurile găsite. Matricea are o proprietate index, care conține numărul caracterului de la care a avut loc potrivirea.

Șirurile au o metodă de potrivire pentru a potrivi modelele și o metodă de căutare care returnează doar poziția de pornire a apariției. Metoda de înlocuire poate înlocui aparițiile unui model cu un alt șir. În plus, puteți trimite către funcția de înlocuire, care va construi o linie de înlocuire pe baza modelului și a grupurilor găsite.

Caracterele obișnuite au setări care sunt scrise după bara oblică de închidere. Opțiunea i face ca expresia regulată să nu țină seama de majuscule și minuscule, iar opțiunea g o face globală, ceea ce, printre altele, face ca metoda de înlocuire să înlocuiască toate aparițiile găsite, nu doar prima.

Constructorul RegExp poate fi folosit pentru a crea expresii regulate din șiruri.

Regulatoarele sunt un instrument ascuțit cu un mâner inconfortabil. Ele simplifică foarte mult unele sarcini și pot deveni imposibil de gestionat atunci când rezolvă altele, sarcini complexe. O parte a învățării să folosești regex este să poți rezista tentației de a-l umple cu o sarcină pentru care nu este destinat.

Exerciții

Inevitabil, atunci când rezolvi probleme, vei întâlni cazuri de neînțeles, iar uneori s-ar putea să disperi când vezi comportamentul imprevizibil al unor expresii regulate. Uneori ajută să studiezi comportamentul unui motor obișnuit printr-un serviciu online precum debuggex.com, unde poți vedea vizualizarea acestuia și îl poți compara cu efectul dorit.
Golf obișnuit
„Golf” în cod este un joc în care trebuie să exprimi un anumit program într-un număr minim de caractere. Golful obișnuit este un exercițiu practic de a scrie cei mai mici obișnuiți posibil pentru a găsi un model dat și doar atât.

Pentru fiecare dintre sublinii, scrieți o expresie regulată pentru a verifica locația lor în linie. Motorul obișnuit ar trebui să găsească numai aceste subșiruri specificate. Nu vă faceți griji cu privire la limitele cuvintelor decât dacă sunt menționate în mod specific. Când aveți un model obișnuit de lucru, încercați să îl reduceți.

Mașină și pisică
- pop și prop
- dihor, feribot și ferrari
- Orice cuvânt care se termină în ious
- Un spațiu urmat de un punct, virgulă, două puncte sau punct și virgulă.
- Un cuvânt mai lung de șase litere
- Cuvânt fără litere e

// Introduceți expresiile regulate verify(/.../, ["mașina mea", "pisicile rele"], ["camper", "high art"]); verifică(/.../, ["cultură pop", "recuzită nebună"], ["plop"]); verifica(/.../, ["dihor", "feribot", "ferrari"], ["ferrum", "transfer A"]); verifica(/.../, [„cât de delicios”, „cameră spațioasă”], [„ruinator”, „conștiință”]); verifică(/.../, ["punctuație proastă."], [" scăpa de punct"]); verifica(/.../, ["hottentottententen"], ["nu", "hotten totten tenten"]); verifică(/.../, ["ornitorincul roșu", "cuib clătinând" ], ["earth bed", "learning ape"]); function verify(regexp, yes, no) ( // Ignora exercitiile neterminate if (regexp.source == "...") return; yes.forEach(function (s) ( if (!regexp.test(s)) console.log("Nu a fost găsit "" + s + """); )); ) )) console.log("Apariția neașteptată a lui "" + s + """ ));

Citate în text
Să presupunem că ai scris o poveste și peste tot ai indicat dialoguri ghilimele simple. Acum doriți să înlocuiți ghilimelele de dialog cu ghilimele duble și să lăsați ghilimele simple în abrevieri pentru cuvinte ca nu sunt.

Veniți cu un model care să facă distincția între aceste două utilizări ale ghilimelelor și scrieți un apel la metoda înlocuire care face înlocuirea.

Din nou numere
Secvențele de numere pot fi găsite cu o expresie regulată simplă /\d+/.

Scrieți o expresie care să găsească numai numerele scrise în Stilul JavaScript. Trebuie să suporte un posibil minus sau plus înaintea numărului, un punct zecimal și notația științifică 5e-3 sau 1E10 - din nou cu un posibil plus sau minus. De asemenea, rețineți că este posibil să nu existe neapărat numere înainte sau după punct, dar numărul nu poate consta dintr-un singur punct. Adică .5 sau 5. – numere valide, dar un punct în sine nu este.

// Introduceți secvența obișnuită aici. var număr = /^...$/; // Teste: ["1", "-1", "+15", "1.55", ".5", "5.", "1.3e2", "1E-4", "1e+12"] .forEach(funcție(i) ( dacă (!număr.test(e)) console.log("Nu am găsit "" + s + """); )); ["1a", "+-1", "1.2.3", "1+1", "1e4.5", ".5.", "1f5", "."].forEach(funcție(i) ( if (număr.test(e)) console.log("Acceptat incorect "" + s + """); ));

Unii oameni, când se confruntă cu o problemă, gândesc: „Oh, voi folosi expresii obișnuite”. Acum au două probleme.
Jamie Zawinski

Yuan-Ma a spus: „Este nevoie de multă forță pentru a tăia lemnul peste granulația lemnului. Este nevoie de mult cod pentru a programa în structura problemei.
Maestrul Yuan-Ma, „Cartea programării”

Instrumentele și tehnicile de programare supraviețuiesc și se răspândesc într-o manieră evolutivă haotică. Uneori nu cei frumoși și străluciți supraviețuiesc, ci pur și simplu cei care funcționează suficient de bine în domeniul lor - de exemplu, dacă sunt integrati într-o altă tehnologie de succes.

În acest capitol, vom discuta despre un astfel de instrument - expresiile regulate. Acesta este un mod de a descrie modele în date șir. Ei creează un limbaj mic, de sine stătător, care este inclus în JavaScript și în multe alte limbi și instrumente.

Programele regulate sunt atât foarte ciudate, cât și extrem de utile. Sintaxa lor este criptică, iar interfața lor de programare JavaScript este greoaie. Dar este un instrument puternic pentru explorarea și manipularea șirurilor. Odată ce le înțelegi, vei deveni un programator mai eficient.

Crearea unei expresii regulate

Regular – tip de obiect. Poate fi creat apelând constructorul RegExp sau scriind șablonul dorit, înconjurat de bare oblice.

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

Ambele expresii regulate reprezintă același model: caracterul „a” urmat de caracterul „b” urmat de caracterul „c”.

Dacă utilizați constructorul RegExp, atunci modelul este scris ca un șir obișnuit, deci se aplică toate regulile privind barele oblice inverse.

A doua intrare, unde modelul este între bare oblice, tratează diferit barele oblice inverse. În primul rând, deoarece modelul se termină cu o oblică înainte, trebuie să punem o bară oblică inversă înaintea barei oblice pe care dorim să o includem în modelul nostru. În plus, barele oblice inverse care nu fac parte din caractere speciale precum \n vor fi păstrate (mai degrabă decât ignorate ca în șiruri de caractere) și vor schimba semnificația modelului. Unele caractere, cum ar fi semnul de întrebare sau plus, au o semnificație specială în expresiile obișnuite și, dacă trebuie să potriviți un astfel de caracter, acesta trebuie să fie precedat și de o bară oblică inversă.

Var eighteenPlus = /eighteen\+/;

Pentru a ști ce caractere trebuie să fie precedate de o bară oblică, trebuie să înveți o listă cu toate caracterele speciale din expresiile regulate. Acest lucru nu este încă posibil, așa că atunci când aveți îndoieli, puneți o bară oblică inversă în fața oricărui caracter care nu este o literă, un număr sau un spațiu.

Se verifică potriviri

Obisnuitii au mai multe metode. Cel mai simplu este testul. Dacă îi treceți un șir, acesta va returna o valoare booleană care indică dacă șirul conține o apariție a modelului dat.

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

O secvență obișnuită constând numai din caractere nespeciale este pur și simplu o secvență a acestor caractere. Dacă abc este oriunde în linia pe care o testăm (nu doar la început), testul va returna true.

Caut un set de personaje

De asemenea, puteți afla dacă un șir conține abc folosind indexOf. Modelele obișnuite vă permit să mergeți mai departe și să creați modele mai complexe.

Să presupunem că trebuie să găsim orice număr. Când punem un set de caractere între paranteze drepte în expresia regulată, înseamnă că acea parte a expresiei se potrivește cu oricare dintre caracterele dintre paranteze.

Ambele expresii sunt în linii care conțin un număr.

Console.log(//.test(„în 1992”)); // → adevărat console.log(//.test(„în 1992”)); // → adevărat

Între paranteze drepte, o liniuță între două caractere este utilizată pentru a specifica un interval de caractere, în care secvența este specificată de codarea Unicode. Caracterele de la 0 la 9 sunt acolo doar pe rând (coduri de la 48 la 57), așa că le captează pe toate și se potrivește cu orice număr.

Mai multe grupuri de caractere au propriile lor abrevieri încorporate.

\d Orice număr
\w Caracter alfanumeric
\s caracter de spațiu alb (spațiu, tabulator, linie nouă etc.)
\D nu un număr
\W nu este un caracter alfanumeric
\S nu este un caracter alb
. orice caracter, cu excepția avansului de linie

Astfel, puteți seta formatul de dată și oră ca 30/01/2003 15:20 cu următoarea expresie:

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")); // → fals

Arată groaznic, nu-i așa? Există prea multe bare oblice inverse, ceea ce face modelul dificil de înțeles. Îl vom îmbunătăți puțin mai târziu.

Barele oblice inverse pot fi folosite și între paranteze drepte. De exemplu, [\d.] înseamnă orice număr sau punct. Observați că perioada din paranteze pătrate își pierde semnificația specială și devine pur și simplu o perioadă. Același lucru este valabil și pentru alte caractere speciale, cum ar fi +.

Puteți inversa un set de caractere - adică să spunem că trebuie să găsiți orice caracter, cu excepția celor care sunt în set - prin plasarea unui semn ^ imediat după paranteza pătrată de deschidere.

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

Repetarea părților șablonului

Știm cum să găsim un număr. Ce se întâmplă dacă trebuie să găsim întregul număr - o secvență de una sau mai multe cifre?

Dacă puneți semnul + după ceva în secvența obișnuită, aceasta va însemna că acest element poate fi repetat de mai multe ori. /\d+/ înseamnă una sau mai multe cifre.

Console.log(/"\d+"/.test(""123"")); // → adevărat console.log(/"\d+"/.test("""")); // → false console.log(/"\d*"/.test(""123"")); // → adevărat console.log(/"\d*"/.test("""")); // → adevărat

Asteriscul * are aproape aceeași semnificație, dar permite ca modelul să apară de zero ori. Dacă ceva este urmat de un asterisc, atunci nu împiedică niciodată modelul să fie în linie - apare doar acolo de zero ori.

Un semn de întrebare face ca o parte a modelului să fie opțională, ceea ce înseamnă că poate apărea zero sau o dată. În exemplul următor, poate apărea caracterul u, dar modelul se potrivește chiar și atunci când nu apare.

Var vecin = /neighbou?r/; console.log(vecin.test(„vecin”); // → adevărat console.log(vecin.test(„vecin”); // → adevărat

Acoladele sunt folosite pentru a specifica de câte ori trebuie să apară un model. (4) după un element înseamnă că trebuie să apară de 4 ori în linie. De asemenea, puteți specifica un interval: (2,4) înseamnă că elementul trebuie să apară de cel puțin 2 și nu mai mult de 4 ori.

O altă versiune a formatului de dată și oră, în care zilele, lunile și orele de una sau două cifre sunt permise. Și este, de asemenea, puțin mai lizibil.

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

Puteți folosi spații deschise omițând unul dintre numere. (,5,) înseamnă că modelul poate apărea de la zero la cinci ori, iar (5,) înseamnă de la cinci sau mai multe.

Gruparea subexpresiilor

Pentru a utiliza operatorii * sau + pe mai multe elemente simultan, puteți folosi paranteze. Partea expresiei regulate cuprinsă între paranteze este considerată un element din punctul de vedere al operatorilor.

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

Primul și al doilea plus se aplică numai celui de-al doilea O din boo și hoo. Al treilea + se referă la întregul grup (hoo+), găsind una sau mai multe astfel de secvențe.

Litera i de la sfârșitul expresiei face ca expresia regulată să nu țină seama de majuscule și minuscule - astfel încât B se potrivește cu b.

Meciuri și grupe

Metoda de testare este cea mai simplă metodă de verificare a expresiilor regulate. Vă spune doar dacă o potrivire a fost găsită sau nu. Obișnuiții au, de asemenea, o metodă exec, care va returna null dacă nu a fost găsit nimic și, în caz contrar, va returna un obiect cu informații despre potrivire.

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

Obiectul returnat de exec are o proprietate index, care conține numărul caracterului de la care a avut loc potrivirea. În general, obiectul arată ca o matrice de șiruri, unde primul element este șirul care a fost verificat pentru o potrivire. În exemplul nostru, aceasta va fi succesiunea de numere pe care o căutam.

Șirurile au o metodă de potrivire care funcționează în același mod.

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

Când o expresie obișnuită conține subexpresii grupate prin paranteze, textul care se potrivește cu aceste grupuri va apărea de asemenea în matrice. Primul element este întotdeauna o potrivire completă. A doua este partea care s-a potrivit cu primul grup (cel ale cărui paranteze au apărut mai întâi), apoi al doilea grup și așa mai departe.

Var quotedText = /"([^"]*)"/; console.log(quotedText.exec ("ea a spus "bună"")); // → [""bună ziua", "bună ziua"]

Când un grup nu este găsit deloc (de exemplu, dacă este urmat de un semn de întrebare), poziția sa în matrice este nedefinită. Dacă un grup se potrivește de mai multe ori, atunci numai ultimul meci va fi în matrice.

Console.log(/bad(ly)?/.exec(„rea”); // → [„prost”, nedefinit] console.log(/(\d)+/.exec(„123”)); // → ["123", "3"]

Grupurile sunt utile pentru a prelua părți de șiruri. Dacă nu vrem doar să verificăm dacă un șir are o dată, ci să îl extragem și să creăm un obiect reprezentând data, putem include secvențele de numere în paranteze și selectam data din rezultatul exec.

Dar mai întâi, o mică digresiune în care vom afla modul preferat de a stoca data și ora în JavaScript.

Tipul de dată

JavaScript are un tip de obiect standard pentru date – mai precis, momente în timp. Se numește Data. Dacă pur și simplu creați un obiect dată folosind new, veți obține data și ora curente.

Console.log(data noua()); // → Duminica 09 noiembrie 2014 00:07:57 GMT+0300 (CET)

De asemenea, puteți crea un obiect care conține un anumit timp

Console.log(new Date(2015, 9, 21)); // → Miercuri 21 octombrie 2015 00:00:00 GMT+0300 (CET) console.log(new Date(2009, 11, 9, 12, 59, 59, 999)); // → miercuri 09 decembrie 2009 12:59:59 GMT+0300 (CET)

JavaScript folosește o convenție în care numerele lunii încep cu zero și numerele zilei cu unu. Acest lucru este stupid și ridicol. Atenție.

Ultimele patru argumente (ore, minute, secunde și milisecunde) sunt opționale și sunt setate la zero dacă lipsesc.

Marcajele de timp sunt stocate ca număr de milisecunde care au trecut de la începutul anului 1970. Pentru perioadele înainte de 1970, sunt folosite numere negative (acest lucru se datorează convenției de timp Unix care a fost creată în acea perioadă). Metoda getTime a obiectului data returnează acest număr. Este în mod natural mare.
console.log(new Date(2013, 11, 19).getTime()); // → 1387407600000 console.log(new Date(1387407600000)); // → Joi, 19 decembrie 2013 00:00:00 GMT+0100 (CET)

Dacă dați constructorului Date un argument, acesta este tratat ca acest număr de milisecunde. Puteți obține valoarea curentă în milisecunde creând un obiect Date și apelând metoda getTime sau apelând funcția Date.now.

Obiectul Date are metode getFullYear, getMonth, getDate, getHours, getMinutes și getSeconds pentru a prelua componentele sale. Există, de asemenea, o metodă getYear care returnează un cod de două cifre destul de inutil, cum ar fi 93 sau 14.

Prin includerea părților relevante ale șablonului în paranteze, putem crea un obiect dată direct din șir.

Funcția findDate(șir) ( var dateTime = /(\d(1,2))-(\d(1,2))-(\d(4))/; var potrivire = dateTime.exec(șir); return new Date(Număr(potrivire), Număr(potrivire) - 1, Număr(potrivire) ) console.log(findDate("30-1-2003")); // → Joi, 30 ianuarie 2003 00:00:00 GMT+0100 (CET)

Limite de cuvinte și linii

Din păcate, findDate va extrage la fel de fericit și data fără sens 00-1-3000 din șirul „100-1-30000”. Potrivirea se poate întâmpla oriunde în șir, așa că în acest caz va începe pur și simplu la al doilea caracter și se va termina la penulul caracter.

Dacă trebuie să forțăm potrivirea să preia întregul șir, folosim etichetele ^ și $. ^ se potrivește cu începutul liniei, iar $ se potrivește cu sfârșitul. Prin urmare, /^\d+$/ se potrivește unui șir care conține doar una sau mai multe cifre, /^!/ se potrivește unui șir care începe cu un semn de exclamare și /x^/ nu se potrivește cu niciun șir (nu poate exista un x).

Dacă, pe de altă parte, vrem doar să ne asigurăm că data începe și se termină la granița unui cuvânt, folosim semnul \b. O limită a unui cuvânt poate fi începutul sau sfârșitul unei linii sau orice loc dintr-o linie unde există un caracter alfanumeric \w pe o parte și un caracter nealfanumeric pe cealaltă parte.

Console.log(/cat/.test(„concatenate”)); // → true console.log(/\bcat\b/.test(„concatenate”)); // → fals

Rețineți că eticheta de delimitare nu este un simbol. Este pur și simplu o constrângere, ceea ce înseamnă că o potrivire are loc numai dacă este îndeplinită o anumită condiție.

Șabloane cu alegere

Să presupunem că trebuie să aflați dacă textul conține nu doar un număr, ci un număr urmat de porc, vaca sau pui la singular sau plural.

Ar fi posibil să scrieți trei expresii regulate și să le verificați una câte una, dar există o modalitate mai bună. Simbol | denotă o alegere între modelele din stânga și din dreapta acestuia. Și putem spune următoarele:

Var animalCount = /\b\d+ (porc|vacă|pui)s?\b/; console.log(animalCount.test("15 porci"); // → true console.log(animalCount.test("15 pui de porc")); // → fals

Parantezele delimitează porțiunea modelului la care se aplică | și mulți astfel de operatori pot fi plasați unul după altul pentru a indica o alegere dintre mai mult de două opțiuni.

Motor de căutare

Expresiile regulate pot fi considerate diagrame de flux. Următoarea diagramă descrie un exemplu recent de animale.

O expresie se potrivește cu un șir dacă este posibil să găsiți o cale din partea stângă a diagramei la dreapta. Ne amintim poziția curentă în linie și de fiecare dată când trecem prin dreptunghi, verificăm dacă partea de linie imediat după poziția noastră în ea se potrivește cu conținutul dreptunghiului.

Aceasta înseamnă că verificarea dacă caracterul nostru obișnuit se potrivește cu șirul „cei 3 porci” atunci când parcurgeți diagrama de flux arată astfel:

La poziția 4 există o limită de cuvânt și trecem de primul dreptunghi
- incepand din pozitia a 4-a gasim numarul si trecem prin al doilea dreptunghi
- la poziția 5, o cale se închide înapoi în fața celui de-al doilea dreptunghi, iar a doua merge mai departe către dreptunghi cu un spațiu. Avem un spațiu, nu un număr și alegem a doua cale.
- acum suntem pe pozitia 6, inceputul “porcilor”, si la tripla ramificare a potecilor. Nu există „vacă” sau „pui” în linie, dar există „porc”, așa că alegem această cale.
- în poziția 9 după bifurcația triplă, o cale ocolește „s” și merge la ultimul dreptunghi de limită a cuvântului, iar a doua trece prin „s”. Avem un „s”, așa că mergem acolo.
- la poziția 10 suntem la sfârșitul liniei și doar limita cuvântului se poate potrivi. Capătul liniei este considerat graniță și trecem prin ultimul dreptunghi. Și acum am găsit cu succes șablonul nostru.

Practic, modul în care funcționează expresiile regulate este că algoritmul începe la începutul șirului și încearcă să găsească o potrivire acolo. În cazul nostru, există o limită a cuvântului, deci trece de primul dreptunghi - dar nu există niciun număr acolo, așa că se împiedică de al doilea dreptunghi. Apoi trece la al doilea caracter din șir și încearcă să găsească o potrivire acolo... Și așa mai departe până când găsește o potrivire sau ajunge la sfârșitul șirului, caz în care nu se găsește nicio potrivire.

Kickback-uri

Expresia regulată /\b(+b|\d+|[\da-f]h)\b/ se potrivește fie cu un număr binar urmat de un b, cu un număr zecimal fără sufix, fie cu un număr hexazecimal (numerele de la 0 la 9 sau simbolurile de la a la h), urmate de h. Diagrama relevanta:

Când căutați o potrivire, se poate întâmpla ca algoritmul să ia calea de sus (număr binar), chiar dacă nu există un astfel de număr în șir. Dacă există o linie „103”, de exemplu, este clar că numai după ce ajunge la numărul 3 algoritmul va înțelege că este pe calea greșită. În general, linia se potrivește cu secvența obișnuită, doar că nu în acest fir.

Apoi algoritmul revine. La o bifurcație, își amintește poziția curentă (în cazul nostru, acesta este începutul liniei, imediat după limita cuvântului), astfel încât să puteți întoarce înapoi și să încercați o altă cale dacă cea aleasă nu funcționează. Pentru șirul „103”, după ce a întâlnit un trei, se va întoarce și va încerca să treacă prin calea zecimală. Acest lucru va funcționa, astfel încât o potrivire va fi găsită.

Algoritmul se oprește imediat ce găsește o potrivire completă. Aceasta înseamnă că, chiar dacă mai multe opțiuni pot fi potrivite, se folosește doar una dintre ele (în ordinea în care apar în secvența obișnuită).

Backtracking apare atunci când se utilizează operatori de repetiție precum + și *. Dacă căutați /^.*x/ în șirul „abcxe”, partea regex.* va încerca să consume întregul șir. Algoritmul va realiza apoi că are nevoie și de „x”. Deoarece nu există niciun „x” după sfârșitul șirului, algoritmul va încerca să caute o potrivire deplasând înapoi cu un caracter. După abcx nu există nici un x, apoi se întoarce din nou, de data aceasta la subșirul abc. Iar după linie, găsește x și raportează o potrivire reușită, în pozițiile de la 0 la 4.

Puteți scrie o rutină obișnuită care va duce la mai multe derulări. Această problemă apare atunci când modelul se poate potrivi cu intrarea în multe moduri diferite. De exemplu, dacă facem o greșeală când scriem expresia regulată pentru numere binare, s-ar putea să scriem accidental ceva de genul /(+)+b/.

Dacă algoritmul ar căuta un astfel de model într-un șir lung de 0 și 1 care nu avea un „b” la sfârșit, ar trece mai întâi prin bucla interioară până când rămâne fără cifre. Apoi va observa că nu există un „b” la sfârșit, va întoarce o poziție înapoi, va trece prin bucla exterioară, va renunța din nou, va încerca să se rotească înapoi într-o altă poziție de-a lungul buclei interioare... Și va continua pentru a căuta în acest fel, folosind ambele bucle. Adică, cantitatea de lucru cu fiecare caracter al liniei se va dubla. Chiar și pentru câteva zeci de personaje, găsirea unei potriviri va dura foarte mult timp.

metoda înlocuirii

Șirurile au o metodă de înlocuire care poate înlocui o parte dintr-un șir cu un alt șir.

Console.log("tata".replace("p", "m")); // → hartă

Primul argument poate fi și o expresie regulată, caz în care prima apariție a expresiei regulate din linie este înlocuită. Când opțiunea „g” (globală) este adăugată la o expresie regulată, toate aparițiile sunt înlocuite, nu doar prima

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

Ar fi logic să treceți opțiunea „înlocuiți tot” printr-un argument separat sau printr-o metodă separată, cum ar fi replaceAll. Dar, din păcate, opțiunea este transmisă prin sistemul obișnuit în sine.

Puterea deplină a expresiilor regulate este dezvăluită atunci când folosim link-uri către grupuri găsite într-un șir, specificate în expresia regulată. De exemplu, avem o linie care conține numele persoanelor, câte un nume pe rând, în formatul „Nume, prenume”. Dacă trebuie să le schimbăm și să eliminăm virgula pentru a obține „Nume de familie”, scriem următoarele:

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

$1 și $2 în linia de înlocuire se referă la grupuri de caractere cuprinse între paranteze. $1 este înlocuit cu textul care se potrivește cu primul grup, $2 cu al doilea grup și așa mai departe, până la $9. Întreaga potrivire este conținută în variabila $&.

De asemenea, puteți trece o funcție ca al doilea argument. Pentru fiecare înlocuire, va fi apelată o funcție ale cărei argumente vor fi grupurile găsite (și toată partea corespunzătoare a liniei), iar rezultatul acesteia va fi inserat într-o nouă linie.

Exemplu simplu:

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

Iată una mai interesantă:

Stock de var = „1 lămâie, 2 varză și 101 ouă”; funcția minusOne(potrivire, cantitate, unitate) ( cantitate = Număr (cantitate) - 1; dacă (cantitate == 1) // a rămas doar unul, eliminați „s” de la sfârșit unit = unit.slice(0, unit. lungime - 1; else if (cantitate == 0) suma = "nu" + unitate) console.log(stock.replace(/(\d+)/g, minusOne); ); // → fără lămâie, 1 varză și 100 de ouă

Codul ia un șir, găsește toate aparițiile numerelor urmate de un cuvânt și returnează un șir cu fiecare număr redus cu unul.

Grupul (\d+) intră în argumentul cantitate, iar (\w+) intră în argumentul unitate. Funcția convertește suma într-un număr - și aceasta funcționează întotdeauna, deoarece modelul nostru este \d+. Și apoi face modificări la cuvânt, în cazul în care rămâne doar 1 articol.

Lăcomie

Este ușor de utilizat înlocuire pentru a scrie o funcție care elimină toate comentariile din codul JavaScript. Iată prima încercare:

Funcția stripComments(cod) ( return code.replace(/\/\/.*|\/\*[^]*\*\//g, ""); ) console.log(stripComments("1 + /* 2 */3")); // → 1 + 3 console.log(stripComments("x = 10;// zece!")); // → x = 10; console.log(stripComments("1 /* a */+/* b */ 1")); // → 1 1

Partea dinaintea operatorului „sau” se potrivește cu două bare oblice urmate de orice număr de caractere, cu excepția liniilor noi. Partea care elimină comentariile pe mai multe rânduri este mai complexă. Folosim [^], i.e. orice caracter care nu este gol ca o modalitate de a găsi orice personaj. Nu putem folosi un punct, deoarece comentariile de bloc continuă pe o linie nouă, iar caracterul de nouă linie nu se potrivește cu punctul.

Dar rezultatul exemplului anterior este incorect. De ce?

Partea [^]* va încerca mai întâi să capteze cât mai multe personaje. Dacă din această cauză următoarea parte a secvenței obișnuite nu găsește o potrivire, va derula un caracter înapoi și va încerca din nou. În exemplu, algoritmul încearcă să prindă întreaga linie, apoi se derulează înapoi. După ce a derulat înapoi 4 caractere, el va găsi */ în linie - și nu este ceea ce ne-am dorit. Am vrut să luăm un singur comentariu, și nu să mergem la sfârșitul rândului și să găsim ultimul comentariu.

Din această cauză, spunem că operatorii de repetiție (+, *, ? și ()) sunt lacomi, adică mai întâi apucă cât pot și apoi se întorc. Dacă puneți o întrebare după un astfel de operator (+?, *?, ??, ()?), ei se vor transforma în non-lacomi și vor începe să găsească cele mai mici apariții posibile.

Și de asta avem nevoie. Forțând asteriscul să găsească potriviri în numărul minim posibil de caractere dintr-o linie, consumăm doar un bloc de comentarii și nu mai mult.

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

Multe erori apar atunci când se folosesc operatori lacomi în loc de cei care nu sunt lacomi. Când utilizați operatorul de repetare, luați în considerare întotdeauna mai întâi operatorul non-lacom.

Crearea dinamică a obiectelor RegExp

În unele cazuri, modelul exact nu este cunoscut în momentul în care este scris codul. De exemplu, va trebui să căutați numele utilizatorului în text și să-l încadrați în litere de subliniere. Deoarece veți ști numele numai după rularea programului, nu puteți utiliza notația oblică.

Dar puteți construi șirul și utilizați constructorul RegExp. Iată un exemplu:

Var nume = „harry”; var text = „Și Harry are o cicatrice pe frunte.”; var regexp = new RegExp("\\b(" + nume + ")\\b", "gi"); console.log(text.replace(regexp, "_$1_")); // → Și _Harry_ are o cicatrice pe frunte.

Când creăm limite de cuvinte, trebuie să folosim bare oblice duble, deoarece le scriem într-o linie normală, și nu într-o secvență obișnuită cu bare oblice înainte. Al doilea argument la RegExp conține opțiuni pentru expresii regulate - în cazul nostru „gi”, adică. globală și insensibilă la majuscule și minuscule.

Dar dacă numele este „dea+hlrd” (dacă utilizatorul nostru este un kulhatzker)? Ca rezultat, vom obține o expresie regulată fără sens care nu va găsi potriviri în șir.

Putem adăuga bare oblice inverse înaintea oricărui personaj care nu ne place. Nu putem adăuga bare oblice inverse înainte de litere deoarece \b sau \n sunt caractere speciale. Dar puteți adăuga bare oblice înaintea oricăror caractere non-alfanumerice fără probleme.

Var name = "dea+hlrd"; var text = "Acest dea+hlrd enervează pe toată lumea."; var escape = name.replace(/[^\w\s]/g, "\\$&"); var regexp = new RegExp("\\b(" + escape + ")\\b", "gi"); console.log(text.replace(regexp, "_$1_")); // → Această _dea+hlrd_ a enervat pe toată lumea.

metoda de cautare

Metoda indexOf nu poate fi utilizată cu expresii regulate. Dar există o metodă de căutare care așteaptă doar expresia regulată. La fel ca indexOf, returnează indexul primei apariții sau -1 dacă nu apare niciuna.

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

Din păcate, nu există nicio modalitate de a spune metodei să caute o potrivire începând cu un anumit offset (cum poți face cu indexOf). Asta ar fi de ajutor.

proprietate lastIndex

De asemenea, metoda exec nu oferă o modalitate convenabilă de a începe căutarea dintr-o anumită poziție din șir. Dar oferă un mod incomod.

Un obiect regex are proprietăți. Una dintre ele este sursa, care conține un șir. Un altul este lastIndex, care controlează, în anumite condiții, unde va începe următoarea căutare a aparițiilor.

Aceste condiții includ faptul că opțiunea globală g trebuie să fie prezentă și că căutarea trebuie efectuată folosind metoda exec. O soluție mai rezonabilă ar fi să permiteți pur și simplu să se transmită un argument suplimentar către exec, dar caracterul rezonabil nu este o caracteristică fundamentală a interfeței JavaScript regex.

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

Dacă căutarea a avut succes, apelul exec actualizează proprietatea lastIndex pentru a indica poziția după apariția găsită. Dacă nu a avut succes, lastIndex este setat la zero - la fel ca lastIndex al obiectului nou creat.

Atunci când utilizați o variabilă obișnuită globală și apeluri multiple de exec, aceste actualizări automate lastIndex pot cauza probleme. Serviciul dumneavoastră obișnuit poate începe căutarea din poziția rămasă de la apelul anterior.

Var digit = /\d/g; console.log(digit.exec("aici este: 1")); // → ["1"] console.log(digit.exec("și acum: 1")); // → nul

Un alt efect interesant al opțiunii g este că schimbă modul în care funcționează metoda de potrivire. Când este apelat cu această opțiune, în loc să returneze o matrice similară cu rezultatul exec, găsește toate aparițiile modelului din șir și returnează o matrice a subșirurilor găsite.

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

Așa că aveți grijă cu variabilele globale regulate. Cazurile în care sunt necesare - înlocuiți apelurile sau locurile în care utilizați în mod specific lastIndex - sunt probabil toate cazurile în care ar trebui să fie utilizate.

Cicluri de apariție

O sarcină tipică este să iterați prin toate aparițiile unui model dintr-un șir, astfel încât să poată accesa obiectul potrivire din corpul buclei, folosind lastIndex și exec.

Var input = "O linie cu 3 numere în ea... 42 și 88."; număr var = /\b(\d+)\b/g; var potrivire; while (potrivire = număr.exec(intrare)) console.log(„Găsit”, potrivire, „pe”, potrivire.index); // → Găsit 3 la 14 // Găsit 42 la 33 // Găsit 88 la 40

Se profită de faptul că valoarea atribuirii este valoarea atribuită. Folosind match = re.exec(input) ca o condiție într-o buclă while, căutăm la începutul fiecărei iterații, stocăm rezultatul într-o variabilă și încheiem bucla când sunt găsite toate potrivirile.

Analizarea fișierelor INI

Pentru a încheia capitolul, să ne uităm la o problemă folosind expresii regulate. Imaginați-vă că scriem un program care colectează automat informații despre inamicii noștri prin Internet. (Nu vom scrie întregul program, ci doar partea care citește fișierul de setări. Ne pare rău.) Fișierul arată astfel:

Searchengine=http://www.google.com/search?q=$1 spitefulness=9.7 ; se pune punct și virgulă înaintea comentariilor; fiecare secțiune se referă la un inamic diferit nume complet=Larry Doe tip=website taur grădiniță=http://www.geocities.com/CapeCanaveral/11451 fullname=Gargamel tip=vrăjitor rău outputdir=/home/marijn/enemies/gargamel

Formatul exact de fișier (care este destul de utilizat pe scară largă și se numește de obicei INI) este următorul:

Liniile goale și liniile care încep cu punct și virgulă sunt ignorate
- liniile cuprinse între paranteze drepte încep o nouă secțiune
- linii care conțin un identificator alfanumeric urmat de = adăugați o setare în această secțiune

Toate celelalte sunt date incorecte.

Sarcina noastră este să convertim un astfel de șir într-o matrice de obiecte, fiecare cu o proprietate de nume și o matrice de setări. Este necesar un obiect pentru fiecare secțiune, iar altul este necesar pentru setările globale din partea de sus a fișierului.

Deoarece fișierul trebuie analizat linie cu linie, este o idee bună să începeți prin a împărți fișierul în linii. Pentru a face acest lucru, am folosit string.split("\n") în Capitolul 6. Unele sisteme de operare folosesc nu un caracter \n pentru întreruperi de linie, ci două - \r\n. Deoarece metoda split ia ca argument expresiile regulate, putem împărți linii folosind expresia /\r?\n/, permițând atât \n cât și \r\n între linii.

Funcția parseINI(șir) ( // Să începem cu un obiect care conține setări de nivel superior var currentSection = (nume: nul, câmpuri: ); var categorii = ; string.split(/\r?\n/).forEach(funcție (line ) ( var potrivire; if (/^\s*(;.*)?$/.test(line)) ( return; ) else if (match = line.match(/^\[(.*)\) ]$ /)) ( currentSection = (nume: potrivire, câmpuri: ); categories.push(currentSection); ) else if (potrivire = line.match(/^(\w+)=(.*)$/)) ( currentSection. fields.push((nume: potrivire, valoare: potrivire) else ( throw new Error("Linia "" + linia + "" conține date invalide."); ));

Codul parcurge toate liniile, actualizând obiectul secțiunii curente „secțiunea curentă”. În primul rând, verifică dacă linia poate fi ignorată folosind expresia regulată /^\s*(;.*)?$/. Vă puteți imagina cum funcționează asta? Partea dintre paranteze se potrivește cu comentariile, nu? face astfel încât caracterul obișnuit să se potrivească, de asemenea, linii formate doar din spații.

Dacă linia nu este un comentariu, codul verifică dacă începe o nouă secțiune. Dacă da, creează un nou obiect pentru secțiunea curentă, la care se adaugă setările ulterioare.

Ultima posibilitate semnificativă este ca șirul să fie o setare normală, caz în care este adăugat obiectului curent.

Dacă niciuna dintre opțiuni nu funcționează, funcția afișează o eroare.

Observați cum utilizarea frecventă a ^ și $ asigură că expresia se potrivește întregului șir, mai degrabă decât doar o parte a acestuia. Dacă nu le utilizați, codul va funcționa în general, dar uneori va produce rezultate ciudate și eroarea va fi dificil de găsit.

Construcția if (match = string.match(...)) este similară cu trucul de a folosi atribuirea ca condiție într-o buclă while. Adesea nu știi că apelul de potrivire va reuși, așa că poți accesa doar obiectul rezultat în interiorul unui bloc if care îl verifică. Pentru a nu rupe lanțul frumos al verificărilor if, atribuim rezultatul căutării unei variabile și folosim imediat această atribuire ca verificare.

Simboluri internaționale

Datorită implementării inițial simple a limbajului și fixării ulterioare a unei astfel de implementări „în granit”, expresiile regulate JavaScript sunt stupide cu caractere care nu se găsesc în limba engleză. De exemplu, caracterul „litera”, din punctul de vedere al expresiilor regulate JavaScript, poate fi una dintre cele 26 de litere ale alfabetului englez și, din anumite motive, și un caracter de subliniere. Litere precum é sau β, care sunt în mod clar litere, nu se potrivesc cu \w (și se vor potrivi cu \W, care este o non-litera).

Într-o întorsătură ciudată, istoricul \s (spațiu) se potrivește cu toate caracterele care sunt considerate spații albe în Unicode, inclusiv lucruri precum spațiul neîntrerupt sau separatorul de vocale mongole.

Unele implementări regex în alte limbi au sintaxă specială pentru căutarea categoriilor speciale de caractere Unicode, cum ar fi „toate majuscule”, „toate semnele de punctuație” sau „caracterele de control”. Există planuri de a adăuga astfel de categorii la JavaScript, dar ele, aparent, nu vor fi implementate în curând.

Concluzie

Regularii sunt obiecte care reprezintă modele de căutare în șiruri. Ei folosesc propria sintaxă pentru a exprima aceste modele.

/abc/ Secvență de caractere
// Orice caracter din listă
/[^abc]/ Orice caracter, cu excepția caracterelor din listă
// Orice caracter din interval
/x+/ Una sau mai multe apariții ale modelului x
/x+?/ Una sau mai multe apariții, nelacom
/x*/ Zero sau mai multe apariții
/x?/ Zero sau o apariție
/x(2,4)/ De la două până la patru apariții
/(abc)/ Grup
/a|b|c/ Oricare dintre mai multe modele
/\d/ Orice număr
/\w/ Orice caracter alfanumeric („litera”)
/\s/ Orice caracter alb
/./ Orice caracter, cu excepția întreruperilor de rând
/\b/ Limita cuvântului
/^/ Începutul liniei
/$/ Sfârșitul rândului

Regex are o metodă de testare pentru a verifica dacă modelul este în șir. Există o metodă exec care returnează o matrice care conține toate grupurile găsite. Matricea are o proprietate index, care conține numărul caracterului de la care a avut loc potrivirea.

Șirurile au o metodă de potrivire pentru a potrivi modelele și o metodă de căutare care returnează doar poziția de pornire a apariției. Metoda de înlocuire poate înlocui aparițiile unui model cu un alt șir. În plus, puteți trece o funcție de înlocuit care va construi o linie de înlocuire pe baza șablonului și a grupurilor găsite.

Caracterele obișnuite au setări care sunt scrise după bara oblică de închidere. Opțiunea i face ca expresia regulată să nu țină seama de majuscule și minuscule, iar opțiunea g o face globală, ceea ce, printre altele, face ca metoda de înlocuire să înlocuiască toate aparițiile găsite, nu doar prima.

Constructorul RegExp poate fi folosit pentru a crea expresii regulate din șiruri.

Regulatoarele sunt un instrument ascuțit cu un mâner inconfortabil. Ele simplifică foarte mult unele sarcini și pot deveni de negestionat atunci când rezolvăm alte probleme complexe. O parte a învățării să folosești regex este să poți rezista tentației de a-l umple cu o sarcină pentru care nu este destinat.

Exerciții

Inevitabil, atunci când rezolvi probleme, vei întâlni cazuri de neînțeles, iar uneori s-ar putea să disperi când vezi comportamentul imprevizibil al unor expresii regulate. Uneori ajută să studiezi comportamentul unui motor obișnuit printr-un serviciu online precum debuggex.com, unde poți vedea vizualizarea acestuia și îl poți compara cu efectul dorit.
Golf obișnuit
„Golf” în cod este un joc în care trebuie să exprimi un anumit program într-un număr minim de caractere. Golful obișnuit este un exercițiu practic de a scrie cei mai mici obișnuiți posibil pentru a găsi un model dat și doar atât.

Pentru fiecare dintre sublinii, scrieți o expresie regulată pentru a verifica locația lor în linie. Motorul obișnuit ar trebui să găsească numai aceste subșiruri specificate. Nu vă faceți griji cu privire la limitele cuvintelor decât dacă sunt menționate în mod specific. Când aveți un model obișnuit de lucru, încercați să îl reduceți.

Mașină și pisică
- pop și prop
- dihor, feribot și ferrari
- Orice cuvânt care se termină în ious
- Un spațiu urmat de un punct, virgulă, două puncte sau punct și virgulă.
- Un cuvânt mai lung de șase litere
- Cuvânt fără litere e

// Introduceți expresiile regulate verify(/.../, ["mașina mea", "pisicile rele"], ["camper", "high art"]); verifică(/.../, ["cultură pop", "recuzită nebună"], ["plop"]); verifica(/.../, ["dihor", "feribot", "ferrari"], ["ferrum", "transfer A"]); verifica(/.../, [„cât de delicios”, „cameră spațioasă”], [„ruinator”, „conștiință”]); verifică(/.../, ["punctuație proastă."], ["escape the dot"]); verifică(/.../, ["hottenottententen"], ["nu", "hotten totten tenten"]); verifică(/.../, [„ornitorinc roșu”, „cuib clătinat”], [„pat de pământ”, „maimuță care învață”]); function verify(regexp, yes, no) ( // Ignora exercitiile neterminate daca (regexp.source == "...") return; yes.forEach(function(s) ( if (!regexp.test(s))) consola .log("Nu a fost găsită "" + s + """ )); ); ));

Citate în text
Să presupunem că ați scris o poveste și ați folosit ghilimele simple pentru a indica dialogul. Acum doriți să înlocuiți ghilimelele de dialog cu ghilimele duble și să lăsați ghilimele simple în abrevieri pentru cuvinte ca nu sunt.

Veniți cu un model care să facă distincția între aceste două utilizări ale ghilimelelor și scrieți un apel la metoda înlocuire care face înlocuirea.

Din nou numere
Secvențele de numere pot fi găsite cu o expresie regulată simplă /\d+/.

Scrieți o expresie care găsește numai numere scrise în stil JavaScript. Trebuie să suporte un posibil minus sau plus înaintea numărului, un punct zecimal și notația științifică 5e-3 sau 1E10 - din nou cu un posibil plus sau minus. De asemenea, rețineți că este posibil să nu existe neapărat numere înainte sau după punct, dar numărul nu poate consta dintr-un singur punct. Adică, .5 sau 5. sunt numere valide, dar un punct în sine nu este.

// Introduceți secvența obișnuită aici. var număr = /^...$/; // Teste: ["1", "-1", "+15", "1.55", ".5", "5.", "1.3e2", "1E-4", "1e+12"] .forEach(funcție(i) ( dacă (!număr.test(e)) console.log("Nu am găsit "" + s + """); )); ["1a", "+-1", "1.2.3", "1+1", "1e4.5", ".5.", "1f5", "."].forEach(funcție(i) ( if (număr.test(e)) console.log("Acceptat incorect "" + s + """); ));