ti-enxame.com

Como posso encontrar a localização de uma correspondência de expressão regular em Perl?

Eu preciso escrever uma função que recebe uma string e um regex. Preciso verificar se há uma correspondência e retornar a localização inicial e final de uma partida. (O regex já foi compilado por qr//.)

A função também pode receber um sinalizador "global" e, em seguida, preciso retornar os pares (início, fim) de todas as correspondências.

Eu não posso alterar o regex, nem mesmo adicionar () em torno dele, pois o usuário pode usar () e \1. Talvez eu possa usar (?:).

Exemplo: dado "ababab" e o regex qr/ab/, no caso global eu preciso recuperar 3 pares de (início, fim).

32
szabgab

As variáveis ​​incorporadas @- e @+ mantêm as posições inicial e final, respectivamente, da última correspondência bem-sucedida. $-[0] e $+[0] correspondem a todo o padrão, enquanto $-[N] e $+[N] correspondem aos submarcas $N ($1, $2, etc.).

72
Michael Carman

Esqueça o meu post anterior, tenho uma ideia melhor.

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
}

Essa técnica não altera a regex de forma alguma.

Editado para adicionar: para citar de perlvar on $ 1 .. $ 9. "Essas variáveis ​​são todas somente leitura e dinamicamente escopo para o bloco atual." Em outras palavras, se você quiser usar $ 1 .. $ 9, você não pode usar uma sub-rotina para fazer a correspondência.

19
Leon Timmermans

A função pos lhe dá a posição da partida. Se você colocar seu regex entre parênteses, poderá obter o comprimento (e, portanto, o final) usando length $1. Como isso

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
}
10
Leon Timmermans
#!/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"; 
}
0
Shicheng Guo

Você também pode usar a variável $ `depreciada, se você estiver disposto a ter todas as REs em seu programa mais lentas. 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".
0
zigdon