2008-09-17 9 views
30

Necesito escribir una función que reciba una cadena y una expresión regular. Necesito comprobar si hay una coincidencia y devolver la ubicación inicial y final de una coincidencia. (La expresión regular ya estaba compilada por qr//).¿Cómo puedo encontrar la ubicación de una coincidencia de expresiones regulares en Perl?

La función también podría recibir un indicador "global" y luego debo devolver los pares (inicio, fin) de todas las coincidencias.

No puedo cambiar la expresión regular, ni siquiera agregue () a su alrededor ya que el usuario podría usar () y \1. Tal vez pueda usar (?:).

Ejemplo: dado "ababab" y la expresión regular qr/ab/, en el caso global necesito recuperar 3 pares de (inicio, fin).

+0

En cuanto a la interpretación de Leon vs mi propia es posible que desee para aclarar si el indicador se corresponde con el modificador/g o cualquier() captura en la expresión regular. –

Respuesta

10

La función pos le brinda la posición de la coincidencia. Si coloca su expresión regular entre paréntesis, puede obtener la longitud (y por lo tanto el final) usando length $1. Al igual que este

sub match_positions { 
    my ($regex, $string) = @_; 
    return if not $string =~ /($regex)/; 
    return (pos($string), pos($string) + length $1); 
} 
sub all_match_positions { 
    my ($regex, $string) = @_; 
    my @ret; 
    while ($string =~ /($regex)/g) { 
     push @ret, [pos($string), pos($string) + length $1]; 
    } 
    return @ret 
} 
+1

esto parece totalmente incorrecto. en lugar de pos, use pos ($ string) en all_match_positions, en el otro caso, match_positions no funciona en absoluto – Aftershock

+0

@Aftershock: ¡tiene toda la razón! Oops! –

0

También puede utilizar la variable $ obsoleto ', si usted está dispuesto a tener todas las ER en su programa de ejecutar más lento. De perlvar:

$‘  The string preceding whatever was matched by the last successful pattern match (not 
      counting any matches hidden within a BLOCK or eval enclosed by the current BLOCK). 
      (Mnemonic: "`" often precedes a quoted string.) This variable is read-only. 

      The use of this variable anywhere in a program imposes a considerable performance penalty 
      on all regular expression matches. See "BUGS". 
17

Olvide mi publicación anterior, tengo una idea mejor.

sub match_positions { 
    my ($regex, $string) = @_; 
    return if not $string =~ /$regex/; 
    return ($-[0], $+[0]); 
} 
sub match_all_positions { 
    my ($regex, $string) = @_; 
    my @ret; 
    while ($string =~ /$regex/g) { 
     push @ret, [ $-[0], $+[0] ]; 
    } 
    return @ret 
} 

Esta técnica no modifica la expresión regular de ninguna manera.

Editado para agregar: a la cotización de perlvar en $ 1 .. $ 9. "Estas variables son todas de solo lectura y tienen un alcance dinámico para el BLOQUE actual." En otras palabras, si desea usar $ 1 ... $ 9, no puede usar una subrutina para hacer la comparación.

+0

Creo que esto todavía no funcionará si hay() en la expresión regular – szabgab

+0

Sí, ver mi ETA. –

+0

Puede usar una subrutina para hacer la coincidencia, pero si desea las capturas, deberá usar substr(), @ - y @ + para extraer las coincidencias y devolverlas al usuario. –

70

Las variables integradas @- y @+ mantienen las posiciones inicial y final, respectivamente, de la última coincidencia exitosa. $-[0] y $+[0] corresponden a todo el patrón, mientras que $-[N] y $+[N] corresponden a las subcámaras $N ($1, $2, etc.).

+11

Estas variables mágicas me dan ganas de enojar viniendo de Python; no se mencionan ni siquiera una vez en [perl re docs] (http://perldoc.perl.org/perlre.html). –

+5

perldoc perlvar ;-) – Phil

+3

Tenga en cuenta que $ + [0] etc. (las "posiciones finales") dan el índice del carácter * después de * la coincidencia, no el último carácter de la coincidencia. – TextGeek

0
#!/usr/bin/perl 

# search the postions for the CpGs in human genome 

sub match_positions { 
    my ($regex, $string) = @_; 
    return if not $string =~ /($regex)/; 
    return (pos($string), pos($string) + length $1); 
} 
sub all_match_positions { 
    my ($regex, $string) = @_; 
    my @ret; 
    while ($string =~ /($regex)/g) { 
     push @ret, [(pos($string)-length $1),pos($string)-1]; 
    } 
    return @ret 
} 

my $regex='CG'; 
my $string="ACGACGCGCGCG"; 
my $cgap=3;  
my @pos=all_match_positions($regex,$string); 

my @hgcg; 

foreach my $pos(@pos){ 
    push @hgcg,@$pos[1]; 
} 

foreach my $i(0..($#hgcg-$cgap+1)){ 
my $len=$hgcg[$i+$cgap-1]-$hgcg[$i]+2; 
print "$len\n"; 
} 
Cuestiones relacionadas