Próximas funciones de expresiones regulares

ES2015 introdujo muchas funciones nuevas al lenguaje JavaScript, incluidas mejoras significativas en la sintaxis de expresiones regulares con las marcas Unicode (/u) y fijas (/y). Pero el desarrollo no se detuvo desde entonces. En estrecha colaboración con otros miembros de TC39 (el organismo de estándares de ECMAScript), el equipo de V8 propuso y codiseño varias funciones nuevas para que las expresiones regulares sean aún más potentes.

Actualmente, se están proponiendo estas funciones para que se incluyan en la especificación de JavaScript. Aunque las propuestas no se aceptaron por completo, ya se encuentran en la etapa 3 del proceso de TC39. Implementamos estas funciones detrás de una marca (consulta a continuación) para poder proporcionar comentarios oportunos de diseño y de implementación a los autores de las propuestas correspondientes antes de que se finalice la especificación.

En esta entrada de blog, te ofrecemos una vista previa de este futuro emocionante. Si quieres seguir los próximos ejemplos, habilita las funciones experimentales de JavaScript en chrome://flags/#enable-javascript-harmony.

Capturas con nombre

Las expresiones regulares pueden contener los llamados grupos de captura, que pueden capturar una parte del texto coincidente. Hasta ahora, los desarrolladores solo podían hacer referencia a estas capturas por su índice, que se determina según la posición de la captura dentro del patrón.

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'

Sin embargo, las expresiones regulares ya son notoriamente difíciles de leer, escribir y mantener, y las referencias numéricas pueden agregar más complicaciones. Por ejemplo, en patrones más largos, puede ser complicado determinar el índice de una captura en particular:

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

Peor aún, los cambios en un patrón pueden desplazar los índices de todas las capturas existentes:

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

Las capturas con nombre son una función que se lanzará próximamente y que ayudará a mitigar estos problemas, ya que permite a los desarrolladores asignar nombres a las capturas. La sintaxis es similar a Perl, Java, .Net y 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'

También se puede hacer referencia a las capturas nombradas mediante referencias cruzadas nombradas y a través de 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'

Los detalles completos de esta nueva función están disponibles en la propuesta de especificaciones.

Marca dotAll

De forma predeterminada, el átomo . en las expresiones regulares coincide con cualquier carácter, excepto con los terminadores de línea:

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

Una propuesta presenta el modo dotAll, habilitado a través de la marca /s. En el modo dotAll, . también coincide con los terminadores de línea.

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

Los detalles completos de esta nueva función están disponibles en la propuesta de especificaciones.

Escapes de propiedades Unicode

Con la incorporación de la compatibilidad con Unicode en ES2015, de repente hay muchos más caracteres que podrían considerarse números, por ejemplo, el dígito uno con un círculo: ①, o bien caracteres de palabras, por ejemplo, el carácter chino para nieve: 雪.

Ninguno de estos puede coincidir con \d o \w. Cambiar el significado de estos atajos rompería los patrones de expresión regular existentes.

En su lugar, se están presentando nuevas secuencias de escape de propiedades. Ten en cuenta que solo están disponibles para las expresiones regulares compatibles con Unicode, que se indican con la marca /u.

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

El inverso se puede hacer coincidir con \P.

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

El consorcio Unicode define muchas más propiedades, por ejemplo, para símbolos matemáticos o caracteres hiragana japoneses:

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

Puedes encontrar la lista completa de clases de propiedades Unicode compatibles en la propuesta de especificaciones actual. Para ver más ejemplos, consulta este artículo informativo.

Aserciones de lookbehind

Las aserciones de anulación han sido parte de la sintaxis de expresiones regulares de JavaScript desde el principio. Por fin, se presentan sus contrapartes, las aserciones de búsqueda hacia atrás. Es posible que algunos de ustedes recuerden que esto ya forma parte de V8 desde hace bastante tiempo. Incluso Usamos aserciones de búsqueda hacia atrás en segundo plano para implementar la marca Unicode especificada en ES2015.

El nombre ya describe su significado bastante bien. Ofrece una forma de restringir un patrón para que solo coincida si está precedido por el patrón del grupo de búsqueda hacia atrás. Está disponible en versiones coincidentes y no coincidentes:

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

Para obtener más detalles, consulta nuestra entrada de blog anterior dedicada a las aserciones de lookbehind y los ejemplos en los casos de prueba de V8 relacionados.

Agradecimientos

Esta entrada de blog no estaría completa sin mencionar a algunas de las personas que trabajaron arduamente para que esto sucediera, en especial a los defensores del lenguaje Mathias Bynens, Dan Ehrenberg, Claude Pache, Brian Terlson, Thomas Wood, Gorkem Yakin y el gurú de Irregexp Erik Corry, pero también a todas las personas que contribuyeron a la especificación del lenguaje y a la implementación de estas funciones por parte de V8.

Esperamos que estas nuevas funciones de expresiones regulares te entusiasmen tanto como a nosotros.