web-dev-qa-db-fra.com

Comment puis-je trouver l'emplacement d'un match de regex en Perl?

Je dois écrire une fonction qui reçoit une chaîne et une regex. Je dois vérifier s'il existe une correspondance et renvoyer le début et la fin d'une correspondance. (Le regex a déjà été compilé par qr//.)

La fonction peut également recevoir un drapeau "global" et je dois ensuite renvoyer les paires (début, fin) de toutes les correspondances.

Je ne peux pas changer l'expression régulière, même pas ajouter (), l'utilisateur pouvant utiliser () et \1. Peut-être que je peux utiliser (?:).

Exemple: étant donné "ababab" et l'expression régulière qr/ab/, dans le cas global, je dois récupérer 3 paires de (début, fin).

32
szabgab

Les variables intégrées @- et @+ tiennent respectivement les positions de début et de fin de la dernière correspondance réussie. $-[0] et $+[0] correspondent au motif entier, alors que $-[N] et $+[N] correspondent aux sous-correspondances $N ($1, $2, etc.).

72
Michael Carman

Oubliez mon précédent post, j'ai une meilleure idée.

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
}

Cette technique ne change en rien la regex.

Édité pour ajouter: citer de perlvar sur 1 $ .. 9 $. "Ces variables sont toutes en lecture seule et étendues dynamiquement au BLOCK actuel." En d'autres termes, si vous voulez utiliser $ 1 .. 9 $, vous ne pouvez pas utiliser de sous-programme pour faire la correspondance.

19
Leon Timmermans

La fonction pos vous donne la position du match. Si vous mettez votre expression rationnelle entre parenthèses, vous pouvez obtenir la longueur (et donc la fin) en utilisant length $1. Comme ça

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

Vous pouvez également utiliser la variable $ `obsolète, si vous souhaitez que toutes les RE de votre programme s'exécutent plus lentement. 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