Prossime funzionalità delle espressioni regolari

Jakob Gruber
Yang Guo

ES2015 ha introdotto molte nuove funzionalità nel linguaggio JavaScript, tra cui miglioramenti significativi alla sintassi delle espressioni regolari con i flag Unicode (/u) e permanenti (/y). Ma da allora lo sviluppo non si è fermato. In stretta collaborazione con altri membri del TC39 (l'ente responsabile degli standard ECMAScript), il team V8 ha proposto e sviluppato in collaborazione diverse nuove funzionalità per rendere le espressioni regolari ancora più potenti.

Queste funzionalità sono attualmente proposte per l'inclusione nella specifica JavaScript. Anche se le proposte non sono state pienamente accettate, si trovano già nella Fase 3 del processo TC39. Abbiamo implementato queste funzionalità dietro un flag (vedi di seguito) in modo da poter fornire un feedback tempestivo sulla progettazione e l'implementazione ai rispettivi autori della proposta prima che la specifica venga finalizzata.

Questo post del blog ti offre un'anteprima di questo fantastico futuro. Se vuoi seguire i prossimi esempi, attiva le funzionalità JavaScript sperimentali all'indirizzo chrome://flags/#enable-javascript-harmony.

Acquisizioni con nome

Le espressioni regolari possono contenere le cosiddette acquisizioni (o gruppi), che possono acquisire una parte del testo corrispondente. Finora, gli sviluppatori hanno potuto fare riferimento a queste acquisizioni solo in base al loro indice, che è determinato dalla posizione dell'acquisizione all'interno del pattern.

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'

Tuttavia, le espressioni regolari sono già notoriamente difficili da leggere, scrivere e gestire e i riferimenti numerici possono aggiungere ulteriori complicazioni. Ad esempio, in pattern più lunghi può essere difficile determinare l'indice di una determinata acquisizione:

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

E, peggio ancora, le modifiche a un pattern possono potenzialmente spostare gli indici di tutte le acquisizioni esistenti:

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

Le acquisizioni con nome sono una funzionalità futura che aiuta a mitigare questi problemi consentendo agli sviluppatori di assegnare un nome alle acquisizioni. La sintassi è simile a quella di Perl, Java, .Net e 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'

È possibile fare riferimento alle acquisizioni con nome anche mediante backreference denominati e tramite 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'

I dettagli completi di questa nuova funzionalità sono disponibili nella proposta di specifica.

flag dotAll

Per impostazione predefinita, l'atom . nelle espressioni regolari corrisponde a qualsiasi carattere tranne i caratteri di terminazione di riga:

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

Una proposta introduce la modalità dotAll, attivata tramite il flag /s. In modalità dotAll, . corrisponde anche ai caratteri di terminazione di riga.

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

I dettagli completi di questa nuova funzionalità sono disponibili nella proposta di specifica.

Valori di escape della proprietà Unicode

Con l'introduzione di Unicode nell'ES2015, all'improvviso sono presenti molti altri caratteri che potrebbero essere considerati numeri, ad esempio la cifra cerchiata 1 (1) o caratteri alfanumerici, ad esempio il carattere cinese per la neve: 雪.

Nessuno di questi può essere abbinato a \d o \w. Cambiare il significato di questi comandi rapidi spezzarebbe i modelli di espressioni regolari esistenti.

Al loro posto, verranno introdotte nuove sequenze di escape delle proprietà. Tieni presente che sono disponibili solo per le espressioni regolari Unicode-aware indicate dal flag /u.

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

L'inverso può essere abbinato a \P.

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

Il consorzio Unicode definisce molte altre proprietà, ad esempio per i simboli matematici o i caratteri giapponesi dell'Hiragana:

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

L'elenco completo delle classi di proprietà Unicode supportate è disponibile nell'attuale proposta di specifica. Per altri esempi, consulta questo articolo informativo.

Affermazioni "Lookbehind"

Fin dall'inizio le asserzioni Lookahead fanno parte della sintassi delle espressioni regolari di JavaScript. La loro controparte, le asserzioni "guardate dietro", è stata finalmente introdotta. Alcuni di voi ricorderanno già da tempo questa funzionalità fa parte di V8. Usiamo anche le asserzioni lookbehind sottostanti per implementare il flag Unicode specificato in ES2015.

Il nome descrive già abbastanza bene il suo significato. Consente di limitare un pattern in modo che corrisponda solo se è preceduto dal pattern nel gruppo lookbehind. Sono disponibili sia nella versione corrispondente che in quella non corrispondente:

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

Per ulteriori dettagli, consulta il precedente post del blog dedicato ad andare oltre le affermazioni e gli esempi negli scenari di test V8 correlati.

Ringraziamenti

Questo post del blog non sarebbe completo senza menzionare alcune delle persone che hanno lavorato duramente per raggiungere questo obiettivo: in particolare i campioni linguistici Mathias Bynens, Dan Ehrenberg, Claude Pache, Brian Terlson, Thomas Wood, Gorkem Yakin e il guru di Irregexp che hanno contribuito alla specifica del linguaggio Erik Corry.

Ci auguriamo che tu sia entusiasta quanto noi di queste nuove funzionalità di espressione regolare.