¿Puedo usar expresiones regulares de Perl para hacer coincidir el texto balanceado?

Me gustaría hacer coincidir el texto entre corchetes, etc. en Perl. ¿Cómo puedo hacer eso?


Esta es una pregunta del perlfaq oficial . Estamos importando el perlfaq a Stack Overflow .

Esta es la respuesta oficial de preguntas frecuentes menos cualquier edición posterior.

Su primer bash probablemente sea el módulo Text :: Balanced , que está en la biblioteca estándar de Perl desde Perl 5.8. Tiene una variedad de funciones para tratar con texto complicado. El módulo Regexp :: Common también puede ayudar al proporcionar patrones enlatados que puede usar.

A partir de Perl 5.10, puede hacer coincidir texto equilibrado con expresiones regulares utilizando patrones recursivos. Antes de Perl 5.10, tenías que recurrir a varios trucos, como usar el código Perl en secuencias (??{}) .

Aquí hay un ejemplo usando una expresión regular recursiva. El objective es capturar todo el texto entre corchetes angulares, incluido el texto en corchetes angulares nesteds. Este texto de muestra tiene dos grupos “principales”: un grupo con un nivel de anidación y un grupo con dos niveles de anidación. Hay cinco grupos totales en corchetes angulares:

 I have some  > and  > > and that's it. 

La expresión regular para que coincida con el texto equilibrado utiliza dos características de expresión regular nuevas (para Perl 5.10). Estos están cubiertos en perlre y este ejemplo es una versión modificada de uno en esa documentación.

En primer lugar, al agregar el nuevo posesivo + a cualquier cuantificador se encuentra la coincidencia más larga y no retrocede. Eso es importante ya que desea manejar cualquier paréntesis angulares a través de la recursión, no retroceder. El grupo [^<>]++ encuentra uno o más corchetes no angulares sin retroceder.

En segundo lugar, el nuevo (?PARNO) refiere al sub-patrón en el grupo de captura particular dado por PARNO . En la siguiente expresión regular, el primer grupo de captura encuentra (y recuerda) el texto balanceado, y necesita ese mismo patrón dentro del primer búfer para pasar el texto nested. Esa es la parte recursiva. El (?1) usa el patrón en el grupo de captura externo como una parte independiente de la expresión regular.

Poniéndolo todo junto, tienes:

 #!/usr/local/bin/perl5.10.0 my $string =<<"HERE"; I have some  > and  > > and that's it. HERE my @groups = $string =~ m/ ( # start of capture group 1 < # match an opening angle bracket (?: [^<>]++ # one or more non angle brackets, non backtracking | (?1) # found < or >, so recurse to capture group 1 )* > # match a closing angle bracket ) # end of capture group 1 /xg; $" = "\n\t"; print "Found:\n\t@groups\n"; 

El resultado muestra que Perl encontró los dos grupos principales:

 Found:  >  > > 

Con un poco de trabajo adicional, puede obtener todos los grupos en corchetes angulares, incluso si también están en otros corchetes angulares. Cada vez que obtenga una coincidencia equilibrada, elimine su delimitador externo (ese es el que acaba de emparejar, así que no lo vuelva a hacer) y agréguelo a una cola de cadenas para procesar. Sigue haciéndolo hasta que no obtengas ninguna coincidencia:

 #!/usr/local/bin/perl5.10.0 my @queue =<<"HERE"; I have some  > and  > > and that's it. HERE my $regex = qr/ ( # start of bracket 1 < # match an opening angle bracket (?: [^<>]++ # one or more non angle brackets, non backtracking | (?1) # recurse to bracket 1 )* > # match a closing angle bracket ) # end of bracket 1 /x; $" = "\n\t"; while( @queue ) { my $string = shift @queue; my @groups = $string =~ m/$regex/g; print "Found:\n\t@groups\n\n" if @groups; unshift @queue, map { s/^$//; $_ } @groups; } 

El resultado muestra todos los grupos. Las coincidencias más externas aparecen primero y las coincidencias anidadas más adelante:

 Found:  >  > > Found:  Found:  > Found:  
Intereting Posts