JavaScript Regular Expressions Utover det grunnleggende

I vår tidligere veiledning om vanlige uttrykk i JavaScript lærte du om bruken av vanlige uttrykk og hvordan du skriver noe av dine egne for å matche enkle mønstre.

Etter å ha lest den forrige opplæringen, bør du nå ha en god forståelse av spesialtegn som en backslash og tegn sekvenser som \ w eller \ W. Her er en veldig rask oppsummering av disse tegnsekvensene:

  1. Du kan bruke \ d eller \ D for å matche et tall eller et ikke-siffert tegn i en gitt streng. Tall tegn inneholder 0, 1, 2, 3, 4, 5, 6, 7, 8 og 9. Alle andre tegn vil bli matchet av \ D.
  2. Du kan bruke \ w eller \ W for å matche et ord eller et ikke-ord karakter i en gitt streng. Ordkarakterer inneholder alfabeter, sifre og understrek. Alt annet, som Ј,%, etc., betraktes som et ikke-ord-tegn.
  3. Du kan bruke \ s eller \ S for å matche romtegn eller ikke-mellomrom i en streng. Mellomstyper inkluderer mellomrom, fan, form-feed og linjeinnmatning.

I stedet for å matche ett tegn om gangen, kan du bruke * symbol for å matche det foregående uttrykket null eller flere ganger. De + tegnet vil tilsvarende matche det foregående uttrykket 1 eller flere ganger.

Du kan matche et mønster et bestemt antall ganger ved å legge til n, m til det. Her, n er det minste antall ganger du vil matche det, og m er maksimumsgrensen. Hvis du ikke angir en verdi for m, foregående uttrykk vil bli matchet så mange ganger som mulig.

Du bør sjekke ut min tidligere opplæring dersom noe vi bare dekket er ikke klart. Jeg forklarte alt mer detaljert der.

La oss nå gå videre til noen mer sofistikerte tegnsekvenser i regulære uttrykk, slik at du kan få mest mulig ut av dem og finne ut hvordan du skriver uttrykk som passer til kompliserte mønstre.

Ikke-grådige kamper ved hjelp av ? Karakter

De ? tegn betyr forskjellige ting i forskjellige situasjoner.

Når det brukes alene, matcher dette tegnet uttrykket som kom før det 0 eller 1 ganger. I denne forstand er det det samme som 0,1.

Du kan også bruke ? umiddelbart etter andre kvantifisere som *, + og for å matche det minste mulige antall tegn. Med andre ord, det vil gjøre de grådige kvantifiseringene til ikke-grådige. Dette kan være litt vanskelig å forstå uten å se på levende eksempler, så la oss se et eksempel først.

Vurder følgende setning:

Jeg har blitt tildelt 17321HDGE som bruker-ID mens min venn ble tildelt FHES193EK1.

Nå, la oss se alle kampene som ville blitt returnert av forskjellige kvantifiserende og deres ikke-grådige motpart.

Hvis vi bruker uttrykket / \ D + / g I eksemplet vil det matche en eller flere påfølgende siffertegn. På grunn av det globale flagget vil det være tre kamper: 17321, 193, og 1.

Du bør merke det 193 og 1 betraktes som forskjellige kamper fordi de er skilt av EK.

Følgende eksempel viser kampene uten bruk av noen kvantifikatorer.

var re = / \ d + / g; var teller = 0; var textString = "Jeg har blitt tildelt 17321HDGE som bruker ID mens min venn ble tildelt FHES193EK1."; var match = re.exec (textString); mens (match! == null) console.log (match [0]); match = re.exec (textString); teller ++;  console.log ("Totalt samsvar:" + telling); / * Utgang 17321 193 1 Totalt antall treff: 3 * /

Nå legger du til en ? tegn etter \ d+ vil returnere ni forskjellige kamper. I utgangspunktet, / \ D + /? vil slå hvert siffer karakter i en separat kamp. Hvorfor det?

Det er fordi \ d+ er per definisjon antatt å matche ett eller flere siffer. Siden ? Tegnet skal passe til det minste mulige antall tegn, det samsvarer bare med et enkelt siffer om gangen.

Den ikke-grådige ? quantifier vil returnere 9 mindre singelsifre kamper denne gangen. For korthet har jeg kommentert linjen som logger inn kampene til konsoll.

var re = / \ d +? / g; var teller = 0; var textString = "Jeg har blitt tildelt 17321HDGE som bruker ID mens min venn ble tildelt FHES193EK1."; var match = re.exec (textString); mens (match! == null) // console.log (match [0]); match = re.exec (textString); teller ++;  console.log ("Totalt samsvar:" + telling); / * Utgang Totalt antall kampanjer: 9 * /

La oss ta et annet eksempel. Det vanlige uttrykket / \ W + / vil beholde matchende ordkarakterer så lenge de ikke avbrytes av et ikke-ordtegn som plass. I vårt tilfelle vil det matche hele romavskilt ord som tildelt og 17321HDGE en gang en gang.

Hvis vi erstatter vårt opprinnelige vanlige uttrykk med / \ W + /, vi får 14 forskjellige kamper. I utgangspunktet vil hvert ord være sin egen kamp. Du kan se produksjonen selv ved å kommentere linjen.

var re = / \ w + / g; var teller = 0; var textString = "Jeg har blitt tildelt 17321HDGE som bruker ID mens min venn ble tildelt FHES193EK1."; var match = re.exec (textString); mens (match! == null) // console.log (match [0]); match = re.exec (textString); teller ++;  console.log ("Totalt samsvar:" + telling); / * Utgang Totalt antall kampanjer: 14 * /

Nå endrer du uttrykket til / \ W +? / vil returnere hvert ordkarakter som en separat kamp, ​​og du får 68 kamper.

La oss ta en titt på et siste eksempel før vi fortsetter videre. Det vanlige uttrykket / \ W 4, / Vil returnere alle ordene i setningen vår som er fire tegn eller lenger. Så det samsvarer ha, vært, tildelt, og 17321HDGE, blant andre. Nå snu den til / \ W 4? / ville returnere flere treff fra ord med mer enn fire tegn. I vårt eksempel vil de returnerte kampene være ha, vært, assi, gned, 1732, og 1HGD. Karakteren E ved slutten av 17321HDGE er ikke en del av noen kampfordi det ikke kunne være i gruppen av fire påfølgende ordkarakterer.

var re = / \ w 4, / g; var teller = 0; var textString = "Jeg har blitt tildelt 17321HDGE som bruker ID mens min venn ble tildelt FHES193EK1."; var match = re.exec (textString); mens (match! == null) console.log (match [0]); match = re.exec (textString); teller ++;  console.log ("Totalt samsvar:" + telling); / * Output har blitt tildelt 17321HDGE bruker mens venn tildelt FHES193EK1 Totalt antall kampe: 9 * /

Bruk parenteser med? Karakter

I min tidligere regex-veiledning dekket jeg kort hvordan parenteser kan brukes til å huske en del av en kamp. Når det brukes med a ? karakter, de kan også tjene andre formål.

Noen ganger vil du ha en gruppe tegn som skal samsvare som en enhet. For eksempel kan du være på utkikk etter forekomstene av na en eller to ganger som en kamp i den følgende teksten.

na naa nnaa nana naana

For avklaring, leter du etter den dristige teksten som treff: na naen nnaen (Nana) naenna. Delen i parentesene skal sammenliknes som en enhet, så det teller bare som en kamp.

Nesten alle som nettopp har startet med regex, vil bruke uttrykket / Na 1,2 / med det formål å få det forventede resultatet. I deres sinn, den 1,2 del er ment for å matche en eller to forekomster av n og en sammen. Imidlertid samsvarer det faktisk med en enkelt forekomst av n etterfulgt av 1 eller 2 forekomster av tegnet en.

Jeg har gjort kampene tilbake av / Na 1,2 / i fet skrift for avklaring: na naa nnaa (Na) (na) (NAA) (na). Delene i parentes er separate kamper. Som du kan se, får vi ikke resultatet vi ønsket fordi 1,2 vurderer ikke na å være en enkelt enhet som må matches.

Løsningen her er å bruke parenteser for å fortelle JavaScript for å matche na som en enhet. Men som vi så i den forrige opplæringen, begynner JavaScript å huske kampen på grunn av parentesene.

Hvis du ikke vil ha JavaScript for å huske kampen, må du legge til ?: før gruppen av tegn du prøver å matche. I vårt tilfelle vil det endelige uttrykket bli / (?: na) 1,2 /. Gruppen na vil bli matchet som en enhet nå, og det vil ikke bli husket. Jeg har fremhevet de siste kampene som returneres med dette uttrykket i fet skrift: na naen nnaa (nana) naenna.

Følgende eksempel logger alle kampene til konsollen. Siden det er 6 totale kamper, er totalt antall teller 6.

var re = / (?: na) 1,2 / g; var teller = 0; var textString = "na naa nnaa nana naana"; var match = re.exec (textString); mens (match! == null) console.log (match [0]); match = re.exec (textString); teller ++;  console.log ("Totalt samsvar:" + telling); / * Utbytte etter etternavn Totalt antall kampe: 6 * /

Lookahead og negert Lookahead

Det er mange situasjoner der vi ser for å matche et gitt sett med tegn, men bare hvis de er eller ikke følges av et annet sett med tegn. For eksempel kan du være på utkikk etter ordet epler i en tekst, men vil bare ha de kampene som blir fulgt av er. Vurder følgende setning.

epler er yummy. Vi spiste epler hele dagen. Alle som spiste epler likte dem.

I eksemplet ovenfor vil vi bare ha det første ordet som en kamp. Hver annen forekomst av ordet skal ikke være i kampene.

En måte å oppnå dette på er å bruke følgende regulære uttrykk en (? = b). Ordet vi ønsker å matche er en, og ordet som skulle komme etter en er b. I vårt tilfelle vil uttrykket bli / epler (? = \ Sare) /. Husk at ordet er er ikke inkludert i denne kampen.

var re = / epler (? = \ sare) / g; var teller = 0; var textString = "epler er yummy. Vi spiste epler hele dagen. Alle som spiste epler likte dem."; var match = re.exec (textString); mens (match! == null) console.log (match [0]); match = re.exec (textString); teller ++;  console.log ("Totalt samsvar:" + telling); / * Utgående epler Totalt antall treff: 1 * /

Dette vanlige uttrykket, der vi ser på hva som kommer neste i strengen før du bestemmer deg for om ordet er en kamp, ​​kalles en lookahead.

En meget lignende situasjon ville oppstå hvis du bestemte deg for å matche epler bare hvis det var det ikke etterfulgt av et bestemt sett med tegn. I slike tilfeller må du erstatte ?= med ?! i ditt vanlige uttrykk. Hvis vi leter etter alle forekomster av epler som er ikke etterfulgt av er, vi vil bruke / epler (?! \ Sare) / som vårt vanlige uttrykk. Det vil bli to vellykkede kamper for vår test setning.

var re = / epler (?! \ sare) / g; var teller = 0; var textString = "epler er yummy. Vi spiste epler hele dagen. Alle som spiste epler likte dem."; var match = re.exec (textString); mens (match! == null) console.log (match [0]); match = re.exec (textString); teller ++;  console.log ("Totalt samsvar:" + telling); / * Output epler epler Totalt antall treff: 2 * /

En ting til, du trenger ikke å bruke to separate regulære uttrykk for å finne alle kamper som etterfølges av to av de to ordene. Alt du trenger å gjøre er å legge til røroperatøren mellom disse ordene, og du er god til å gå. For eksempel, hvis du leter etter alle forekomster av eple som blir etterfulgt av er eller var, du bør bruke / epler (\ Sare |?! \ swere) / som ditt vanlige uttrykk.

Siste tanker

I denne opplæringen lærte vi å skrive kompliserte regulære uttrykk for å matche mønstrene vi leter etter. Vi kan bruke spesielle ? tegn for å returnere minimumskravene til det forrige tegnet som en kamp. På samme måte kan vi bruke ? inne parenteser for å sikre at gruppen vi matcher ikke blir husket. 

Til slutt lærte vi at ?= og ?! tegn sekvenser i et vanlig uttrykk gir oss muligheten til å returnere et bestemt sett av tegn som en kamp bare hvis de er eller ikke blir fulgt av et annet gitt sett med tegn.

Hvis du har spørsmål knyttet til denne opplæringen, er du velkommen til å gi meg beskjed, og jeg vil gjøre mitt beste for å forklare dem.