2012-05-14 17 views
8

tengo texto como este:expresiones regulares Perl para extraer bloques de varias líneas

00:00 stuff 
00:01 more stuff 
multi line 
    and going 
00:02 still 
    have 

lo tanto, no tienen un final de la secuencia, sólo un nuevo comienzo bloque.

quiero conseguir de forma recursiva todos los bloques:

1 = 00:00 stuff 
2 = 00:01 more stuff 
multi line 
    and going 

etc

El código de abajo sólo me da esto: mal

$VAR1 = '00:00'; 
$VAR2 = ''; 
$VAR3 = '00:01'; 
$VAR4 = ''; 
$VAR5 = '00:02'; 
$VAR6 = ''; 

¿Qué estoy haciendo?

my $text = '00:00 stuff 
00:01 more stuff 
multi line 
and going 
00:02 still 
have 
    '; 
my @array = $text =~ m/^([0-9]{2}:[0-9]{2})(.*?)/gms; 
print Dumper(@array); 

Respuesta

2

Esto debería hacer el truco. A partir de la siguiente \ d \ d: \ d \ d se considera final de bloque.

$Str = '00:00 stuff 
00:01 more stuff 
multi line 
    and going 
00:02 still 
    have 
00:03 still 
    have' ; 

@Blocks = ($Str =~ m#(\d\d:\d\d.+?(?:(?=\d\d:\d\d)|$))#gs); 

print join "--\n", @Blocks; 
+1

Sus parens no capturar '(?: ...)' son redundantes aquí, como '(=?. ..) 'también puede usar alternancias. Además, me doy cuenta de que todavía no estás escribiendo código "estricto", que en mi libro es malo, ya que fomenta la mala práctica. – TLP

+1

He dado suficiente explicación acerca de ** use (ing) strict ** en el otro hilo. ¿Te importa dejar de hacer esto? – tuxuday

+1

Sí, me importa. ¿Te importaría dejar de publicar código no estricto? Este es un entorno de aprendizaje, no le cuesta * nada * publicar código que aliente buenas prácticas, ¿ahora lo hace? – TLP

0

Su problema es que es .*? no expansivo de la misma manera que .* es codicioso. Cuando no está forzado, coincide lo menos posible, que en este caso es la cadena vacía.

Por lo tanto, necesitará algo después del partido no codicioso para anclar su captura. Se me ocurrió con esta expresión regular:

my @array = $text =~ m/\n?([0-9]{2}:[0-9]{2}.*?)(?=\n[0-9]{2}:|$)/gs; 

Como se ve, que eliminan la opción /m sea capaz de igualar con precisión final de la cadena en la afirmación de preanálisis.

También puede considerar esta solución:

my @array = split /(?=[0-9]{2}:[0-9]{2})/, $text; 
4

Versión 5.10.0 introdujo named capture groups que son útiles para hacer coincidir patrones no triviales.

(?'NAME'pattern)
(?<NAME>pattern)

Un grupo de captura de llamada. Idéntico en todos los aspectos al paréntesis de captura normal () pero por el hecho adicional de que se puede hacer referencia al grupo por nombre en varias construcciones de expresiones regulares (como \g{NAME}) y se puede acceder por nombre después de una coincidencia exitosa a través de %+ o %-. Consulte perlvar para obtener más detalles sobre los valores hash %+ y %-.

Si hay varios grupos de captura distintos con el mismo nombre, el $+{NAME} hará referencia al grupo definido más a la izquierda en la coincidencia.

Los formularios (?'NAME'pattern) y (?<NAME>pattern) son equivalentes.

Los grupos de captura nombrados nos permiten nombrar subpatrones dentro de la expresión regular como se muestra a continuación.

use 5.10.0; # named capture buffers 

my $block_pattern = qr/ 
    (?<time>(?&_time)) (?&_sp) (?<desc>(?&_desc)) 

    (?(DEFINE) 
    # timestamp at logical beginning-of-line 
    (?<_time> (?m:^) [0-9][0-9]:[0-9][0-9]) 

    # runs of spaces or tabs 
    (?<_sp> [ \t]+) 

    # description is everything through the end of the record 
    (?<_desc> 
     # s switch makes . match newline too 
     (?s: .+?) 

     # terminate before optional whitespace (which we remove) followed 
     # by either end-of-string or the start of another block 
     (?= (?&_sp)? (?: $ | (?&_time))) 
    ) 
) 
/x; 

lo uso como en

my $text = '00:00 stuff 
00:01 more stuff 
multi line 
and going 
00:02 still 
have 
    '; 

while ($text =~ /$block_pattern/g) { 
    print "time=[$+{time}]\n", 
     "desc=[[[\n", 
     $+{desc}, 
     "]]]\n\n"; 
} 

Salida:

$ ./blocks-demo 
time=[00:00] 
desc=[[[ 
stuff 
]]] 

time=[00:01] 
desc=[[[ 
more stuff 
multi line 
and going 
]]] 

time=[00:02] 
desc=[[[ 
still 
have 
]]]
+1

Un gran ejemplo de la moderna Perl5 re :) – XoR

Cuestiones relacionadas