23º agosto 2020

Referencias inversas en patrones: \N y \k<nombre>

Podemos utilizar el contenido de los grupos de captura (...) no solo en el resultado o en la cadena de reemplazo, sino también en el patrón en sí.

Referencia inversa por número: \N

Se puede hacer referencia a un grupo en el patrón usando \N, donde N es el número de grupo.

Para aclarar por qué es útil, consideremos una tarea.

Necesitamos encontrar una cadena entre comillas: con cualquiera de los dos tipos, comillas simples '...' o comillas dobles "..." – ambas variantes deben coincidir.

¿Cómo encontrarlas?

Ambos tipos de comillas se pueden poner entre corchetes: ['"](.*?)['"], pero encontrará cadenas con comillas mixtas, como "...' y '...". Eso conduciría a coincidencias incorrectas cuando una cita aparece dentro de otra., como en la cadena "She's the one!" (en este ejemplo los strings no se traducen por el uso de la comilla simple):

let str = `He said: "She's the one!".`;

let regexp = /['"](.*?)['"]/g;

// El resultado no es el que nos gustaría tener
alert( str.match(regexp) ); // "She'

Como podemos ver, el patrón encontró una cita abierta ", luego se consume el texto hasta encontrar la siguiente comilla ', esta cierra la coincidencia.

Para asegurar que el patrón busque la comilla de cierre exactamente igual que la de apertura, se pone dentro de un grupo de captura y se hace referencia inversa al 1ero: (['"])(.*?)\1.

Aquí está el código correcto:

let str = `He said: "She's the one!".`;

let regexp = /(['"])(.*?)\1/g;

alert( str.match(regexp) ); // "She's the one!"

¡Ahora funciona! El motor de expresiones regulares encuentra la primera comilla (['"]) y memoriza su contenido. Este es el primer grupo de captura.

Continuando en el patrón, \1 significa “encuentra el mismo texto que en el primer grupo”, en nuestro caso exactamente la misma comilla.

Similar a esto, \2 debería significar: el contenido del segundo grupo, \3 – del tercer grupo, y así sucesivamente.

Por favor tome nota:

Si usamos ?: en el grupo, entonces no lo podremos referenciar. Los grupos que se excluyen de las capturas (?:...) no son memorizados por el motor.

No confundas: el patrón \1, con el reemplazo: $1

En el reemplazo de cadenas usamos el signo dólar: $1, mientras que en el patrón – una barra invertida \1.

Referencia inversa por nombre: \k<nombre>

Si una regexp tiene muchos paréntesis, es conveniente asignarle nombres.

Para referenciar un grupo con nombre usamos \k<nombre>.

En el siguiente ejemplo, el grupo con comillas se llama ?<quote>, entonces la referencia inversa es \k<quote>:

let str = `He said: "She's the one!".`;

let regexp = /(?<quote>['"])(.*?)\k<quote>/g;

alert( str.match(regexp) ); // "She's the one!"
Mapa del Tutorial

Comentarios

lea esto antes de comentar…
  • Si tiene sugerencias sobre qué mejorar, por favor enviar una propuesta de GitHub o una solicitud de extracción en lugar de comentar.
  • Si no puede entender algo en el artículo, por favor explique.
  • Para insertar algunas palabras de código, use la etiqueta <code>, para varias líneas – envolverlas en la etiqueta <pre>, para más de 10 líneas – utilice una entorno controlado (sandbox) (plnkr, jsbin, codepen…)