2012-10-04 19 views
7

Estoy tratando de hacer coincidir texto como sp { ...{...}... }, donde las llaves se pueden anidar. Esto es lo que tengo hasta ahora:Regex con expresión recursiva para unir llaves anidadas?

my $regex = qr/ 
(     #save $1 
    sp\s+   #start Soar production 
    (    #save $2 
     \{   #opening brace 
     [^{}]*  #anything but braces 
     \}   #closing brace 
     | (?1)  #or nested braces 
    )+    #0 or more 
) 
/x; 

simplemente no puede conseguir que se corresponde con el siguiente texto: sp { { word } }. ¿Alguien puede ver lo que está mal con mi expresión regular?

Respuesta

6

Existen numerosos problemas. El bit debe ser recursivo:

(
    (?: \{ (?-1) \} 
    | [^{}]+ 
    )* 
) 

Todos juntos:

my $regex = qr/ 
    sp\s+ 
    \{ 
     (
     (?: \{ (?-1) \} 
     | [^{}]++ 
     )* 
    ) 
    \} 
/x; 

print "$1\n" if 'sp { { word } }' =~ /($regex)/; 
+0

Justo lo que necesitaba. –

+0

Por lo que puedo decir, la expresión regular no permite espacios alrededor de las llaves (lo siento por la rima) por lo que el caso de prueba debería fallar. ¿Que pasa con eso? – tripleee

+0

Hmmm ... Esto termina tomando para siempre algunas coincidencias parciales, como esta: 'sp {palabra {(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa)}'. –

5

Este es el caso para el Text::Balanced infrautilizada, un módulo básico muy útil para este tipo de cosas. No se basan en la pos del inicio de la secuencia delimitada ser encontrado/set en primer lugar, por lo que suelen alegar ésta como esto:

#!/usr/bin/env perl 

use strict; 
use warnings; 

use Text::Balanced 'extract_bracketed'; 

sub get_bracketed { 
    my $str = shift; 

    # seek to beginning of bracket 
    return undef unless $str =~ /(sp\s+)(?={)/gc; 

    # store the prefix 
    my $prefix = $1; 

    # get everything from the start brace to the matching end brace 
    my ($bracketed) = extract_bracketed($str, '{}'); 

    # no closing brace found 
    return undef unless $bracketed; 

    # return the whole match 
    return $prefix . $bracketed; 
} 

my $str = 'sp { { word } }'; 

print get_bracketed $str; 

la expresión regular con el modificador gc cuenta la cadena de recordar dónde está el punto final de el partido es, y extract_bracketed usa esa información para saber por dónde empezar.

+0

Realmente necesito leer este módulo. Aparece mucho, pero siempre prefiero la expresión regular porque ya he invertido tanto tiempo en aprenderla, es divertido aprender más y me parece más compacta. ¡Gracias por la respuesta! –

+0

@NateGlenn, realmente es complementario a regexp y especialmente a la funcionalidad regexp 'gc' (analizador). Es por eso que usa la 'pos' de la cadena, ya que se espera que entremezcle las llamadas a' text_balanced' con '// gc' –

Cuestiones relacionadas