2009-05-29 11 views
16

¿Es posible que una expresión regular coincida en función de otras partes de la misma expresión regular?Coincidencia en subcadenas repetidas en una expresión regular

Por ejemplo, ¿cómo uniría líneas que comiencen y terminen con la misma secuencia de 3 caracteres, independientemente de cuáles sean los caracteres?

Partidos:

abcabc 
xyz abc xyz 

no coincide:

abc123 

Indefinido: (puede coincidir o no, lo que sea más fácil)

ababa 
a 

Idealmente, me gustaría algo en el sabor Perl Regex. Si eso no es posible, me gustaría saber si hay sabores que puede hacerlo.

Respuesta

19

Utilice los grupos de captura y las referencias retrospectivas.

/^(.{3}).*\1$/ 

El \1 se refiere de nuevo a lo que se corresponde con el contenido del primer grupo de captura (el contenido de la ()). Regexes en la mayoría de los idiomas permiten algo como esto.

+3

Huh, en realidad he estado utilizando grupos de captura y referencias posteriores durante años en la parte de reemplazo de buscar/reemplazar. Nunca pensé que podría usarlos en el patrón de coincidencia original también. – Whatsit

13

Necesita backreferences. La idea es usar un grupo de captura para el primer bit, y luego consultar de nuevo cuando trates de unir el último bit. He aquí un ejemplo de hacer coincidir un par de etiquetas de inicio y fin HTML (desde el enlace que figura anterior):

<([A-Z][A-Z0-9]*)\b[^>]*>.*?</\1> 

Esta expresión regular contiene sólo un par de paréntesis, que captura la cadena igualada por [A-Z][A-Z0-9]* en la primera referencia inversa . Esta referencia inversa se reutiliza con \1 (barra invertida uno). El / antes es simplemente la barra diagonal en la etiqueta HTML de cierre que estamos tratando de hacer coincidir.

Aplicando esto a su caso: (. Sí, eso es la expresión regular que Brian Carper publicada Hay simplemente no hay muchas maneras de hacer esto.)

/^(.{3}).*\1$/ 

Una explicación detallada por el bien de la posteridad (por favor no ser insultado si es por debajo de ti):

  • ^ coincide con el inicio de la línea.
  • (.{3}) toma tres caracteres de cualquier tipo y los guarda en un grupo para referencia futura.
  • .* coincide con cualquier cosa durante el mayor tiempo posible. (No te importa lo que está en el centro de la línea.)
  • \1 coincide con el grupo que fue capturado en el paso 2.
  • $ coincide con el final de la línea.
3

Por los mismos caracteres al principio y al final:

/^(.{3}).*\1$/ 

Esta es una backreference.

1

Esto funciona:

my $test = 'abcabc'; 
print $test =~ m/^([a-z]{3}).*(\1)$/; 

Para que coincida con el comienzo y el final se debe añadir ^ y $ anclas.

Cuestiones relacionadas