Aankomende reguliere expressiefuncties

ES2015 introduceerde veel nieuwe functies in de JavaScript-taal, waaronder aanzienlijke verbeteringen aan de syntaxis van reguliere expressies met de Unicode- ( /u ) en sticky ( /y )-vlaggen. Maar sindsdien is de ontwikkeling niet gestopt. In nauwe samenwerking met andere leden van TC39 (de ECMAScript-standaardorganisatie) heeft het V8-team verschillende nieuwe functies voorgesteld en mede ontworpen om reguliere expressies nog krachtiger te maken.

Deze functies worden momenteel voorgesteld voor opname in de JavaScript-specificatie. Hoewel de voorstellen nog niet volledig zijn aanvaard, bevinden ze zich al in fase 3 van het TC39-proces . We hebben deze functies achter een vlag geïmplementeerd (zie hieronder) om tijdige ontwerp- en implementatiefeedback te kunnen geven aan de respectievelijke auteurs van het voorstel voordat de specificatie is afgerond.

Deze blogpost geeft je een voorproefje van deze opwindende toekomst. Als u de komende voorbeelden wilt volgen, schakelt u experimentele JavaScript-functies in op chrome://flags/#enable-javascript-harmony .

Genoemde opnames

Reguliere expressies kunnen zogenaamde captures (of groepen) bevatten, die een deel van de overeenkomende tekst kunnen vastleggen. Tot nu toe konden ontwikkelaars alleen naar deze opnames verwijzen aan de hand van hun index, die wordt bepaald door de positie van de opname binnen het patroon.

const pattern = /(\d{4})-(\d{2})-(\d{2})/u;
const result = pattern.exec('2017-07-10');
// result[0] === '2017-07-10'
// result[1] === '2017'
// result[2] === '07'
// result[3] === '10'

Maar reguliere expressies zijn al notoir moeilijk te lezen, schrijven en onderhouden, en numerieke verwijzingen kunnen voor verdere complicaties zorgen. Bij langere patronen kan het bijvoorbeeld lastig zijn om de index van een bepaalde opname te bepalen:

/(?:(.)(.(?<=[^(])(.)))/  // Index of the last capture?

En erger nog, veranderingen in een patroon kunnen mogelijk de indices van alle bestaande opnames verschuiven:

/(a)(b)(c)\3\2\1/     // A few simple numbered backreferences.
/(.)(a)(b)(c)\4\3\2/  // All need to be updated.

Benoemde opnames zijn een nieuwe functie die deze problemen helpt verminderen door ontwikkelaars de mogelijkheid te geven namen aan opnames toe te wijzen. De syntaxis is vergelijkbaar met die van Perl, Java, .Net en Ruby:

const pattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
const result = pattern.exec('2017-07-10');
// result.groups.year === '2017'
// result.groups.month === '07'
// result.groups.day === '10'

Er kan ook naar benoemde opnames worden verwezen door benoemde backreferences en via String.prototype.replace :

// Named backreferences.
/(?<LowerCaseX>x)y\k<LowerCaseX>/.test('xyx');  // true

// String replacement.
const pattern = /(?<fst>a)(?<snd>b)/;
'ab'.replace(pattern, '$<snd>$<fst>');                              // 'ba'
'ab'.replace(pattern, (m, p1, p2, o, s, {fst, snd}) => fst + snd);  // 'ba'

Volledige details van deze nieuwe functie zijn beschikbaar in het specificatievoorstel .

dotAll-vlag

Standaard is de . atom in reguliere expressies komt overeen met elk teken, behalve regelafsluitingen:

/foo.bar/u.test('foo\nbar');   // false

Een voorstel introduceert de dotAll-modus, mogelijk gemaakt via de vlag /s . In de dotAll-modus kan . komt ook overeen met lijnterminators.

/foo.bar/su.test('foo\nbar');  // true

Volledige details van deze nieuwe functie zijn beschikbaar in het specificatievoorstel .

Unicode-eigenschap ontsnapt

Nu het Unicode-bewustzijn in ES2015 werd geïntroduceerd, zijn er plotseling veel meer tekens die als getallen kunnen worden beschouwd, bijvoorbeeld het omcirkelde cijfer één: ①; of weloverwogen woordtekens, bijvoorbeeld het Chinese karakter voor sneeuw: 雪.

Geen van deze kan worden gekoppeld aan \d of \w . Het veranderen van de betekenis van deze afkortingen zou bestaande reguliere expressiepatronen doorbreken.

In plaats daarvan worden nieuwe ontsnappingssequenties voor eigenschappen geïntroduceerd . Houd er rekening mee dat ze alleen beschikbaar zijn voor reguliere expressies die Unicode herkennen en die worden aangegeven met de vlag /u .

/\p{Number}/u.test('①');      // true
/\p{Alphabetic}/u.test('雪');  // true

De inverse kan worden vergeleken met \P .

/\P{Number}/u.test('①');      // false
/\P{Alphabetic}/u.test('雪');  // false

Het Unicode-consortium definieert nog veel meer eigenschappen, bijvoorbeeld voor wiskundige symbolen of Japanse Hiragana-tekens:

/^\p{Math}+$/u.test('∛∞∉');                            // true
/^\p{Script_Extensions=Hiragana}+$/u.test('ひらがな');  // true

De volledige lijst met ondersteunde Unicode-eigenschapsklassen kunt u vinden in het huidige specificatievoorstel . Bekijk dit informatieve artikel voor meer voorbeelden.

Kijk achter beweringen

Lookahead-beweringen maken vanaf het begin deel uit van de reguliere expressiesyntaxis van JavaScript. Hun tegenhanger, de look-behind-beweringen, wordt eindelijk geïntroduceerd . Sommigen van jullie herinneren zich misschien dat dit al geruime tijd onderdeel is van V8. We gebruiken zelfs lookbehind-claims onder de motorkap om de Unicode-vlag te implementeren die is gespecificeerd in ES2015.

De naam beschrijft de betekenis al vrij goed. Het biedt een manier om te voorkomen dat een patroon alleen overeenkomt als het wordt voorafgegaan door het patroon in de lookbehind-groep. Het wordt geleverd in zowel bijpassende als niet-overeenkomende smaken:

/(?<=\$)\d+/.exec('$1 is worth about ¥123');  // ['1']
/(?<!\$)\d+/.exec('$1 is worth about ¥123');  // ['123']

Voor meer details kun je onze vorige blogpost raadplegen, gewijd aan lookbehind-beweringen, en voorbeelden in gerelateerde V8-testcases .

Dankbetuigingen

Deze blogpost zou niet compleet zijn zonder enkele van de mensen te noemen die hard hebben gewerkt om dit mogelijk te maken: vooral taalkampioenen Mathias Bynens , Dan Ehrenberg , Claude Pache , Brian Terlson , Thomas Wood , Gorkem Yakin en Irregexp-goeroe Erik Corry ; maar ook alle anderen die hebben bijgedragen aan de taalspecificatie en de implementatie van deze functies in V8.

We hopen dat je net zo enthousiast bent over deze nieuwe reguliere expressiefuncties als wij!