Próximas funciones de expresiones regulares

Jakob Gruber
Yang Guo

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

Actualmente, se proponen estas funciones para incluirlas en la especificación de JavaScript. Si bien 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 sobre el diseño y la implementación a los respectivos autores de propuestas antes de que finalice la especificación.

Esta entrada de blog te ofrece un adelanto de este emocionante futuro. Si quieres seguir los ejemplos que se muestran más adelante, habilita las funciones experimentales de JavaScript en chrome://flags/#enable-javascript-harmony.

Capturas con nombre

Las expresiones regulares pueden contener las llamadas capturas (o grupos), 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 por 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 muy 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 difícil determinar el índice de una captura en particular:

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

Y lo que es peor, los cambios en un patrón pueden cambiar 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 futura que ayuda a mitigar estos problemas, ya que permite que los desarrolladores asignen 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 con nombre mediante referencias inversas con nombre 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 especificación.

marca de dotAll

De forma predeterminada, el átomo . en las expresiones regulares coincide con cualquier carácter, excepto 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 especificación.

Escapadas de la propiedad Unicode

Con el reconocimiento de Unicode que se introdujo en ES2015, de repente hay muchos más caracteres que podrían considerarse números, por ejemplo, el dígito uno encerrado en un círculo: 1; o caracteres de palabras, por ejemplo, el carácter chino para nieve: 雪.

Ninguna de estas opciones puede coincidir con \d ni \w. Cambiar el significado de estas abreviaturas rompería los patrones de expresiones regulares existentes.

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

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

Se puede hacer coincidir el inverso 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 en Hiragana japonés:

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

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

Detrás de aserciones

Las aserciones de búsqueda anticipada forman parte de la sintaxis de expresiones regulares de JavaScript desde el principio. Su equivalente, las aserciones de visualización, finalmente se presentan. Quizás recuerden que hace tiempo que esto forma parte de V8. Incluso usamos aserciones de estilo subyacente para implementar la marca Unicode que se especifica en ES2015.

El nombre ya describe su significado bastante bien. Ofrece una forma de restringir un patrón para que solo coincida si lo precede el patrón del grupo de búsqueda. Viene en variantes 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 buscar aserciones y ejemplos en casos de prueba de V8 relacionados.

Agradecimientos

Esta entrada de blog no estaría completa si no se menciona a algunas de las personas que trabajaron arduamente para lograrlo: especialmente, los campeones del lenguaje Mathias Bynens, Dan Ehrenberg, Claude Pache, Brian Terlson, Thomas Wood, Gorkem Yakin y las funciones de Irregexp, y el gurú de Irregexp, que también implementaron las especificaciones del lenguaje y Vtribup Vtribu8.

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

Salvo que se indique lo contrario, el contenido de esta página está sujeto a la licencia Atribución 4.0 de Creative Commons, y los ejemplos de código están sujetos a la licencia Apache 2.0. Para obtener más información, consulta las políticas del sitio de Google Developers. Java es una marca registrada de Oracle o sus afiliados.

Última actualización: 2017-07-10 (UTC)