it-swarm-eu.dev

Wie finde ich den Speicherort eines Regex-Matches in Perl?

Ich muss eine Funktion schreiben, die eine Zeichenfolge und einen regulären Ausdruck empfängt. Ich muss prüfen, ob es eine Übereinstimmung gibt, und den Start- und Endpunkt einer Übereinstimmung zurückgeben. (Der reguläre Ausdruck wurde bereits von qr// kompiliert.)

Die Funktion könnte auch ein "globales" Flag erhalten und dann muss ich die (Start-, End-) Paare aller Übereinstimmungen zurückgeben.

Ich kann den regulären Ausdruck nicht ändern und auch keinen () hinzufügen, da der Benutzer möglicherweise () und \1 verwendet. Vielleicht kann ich (?:) verwenden.

Beispiel: gegebenes "ababab" und das regex qr/ab/, im globalen Fall muss ich 3 Paare von (Anfang, Ende) zurückbekommen.

32
szabgab

Die integrierten Variablen @- und @+ enthalten die Start- und Endpositionen der letzten erfolgreichen Übereinstimmung. $-[0] und $+[0] entsprechen dem gesamten Muster, während $-[N] und $+[N] den Submatches $N ($1, $2 usw.) entsprechen.

72
Michael Carman

Vergiss meinen vorherigen Beitrag, ich habe eine bessere Idee.

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
}

Diese Technik ändert den Regex in keiner Weise.

Zum Hinzufügen hinzugefügt: Zitat von perlvar auf $ 1 .. $ 9. "Diese Variablen sind alle schreibgeschützt und dynamisch auf den aktuellen BLOCK ausgerichtet." Mit anderen Worten, wenn Sie $ 1 .. $ 9 verwenden möchten, können Sie keine Subroutine für den Abgleich verwenden.

19
Leon Timmermans

Die pos-Funktion gibt Ihnen die Position des Matches an. Wenn Sie Ihren Regex in Klammern setzen, können Sie die Länge (und damit das Ende) mithilfe von length $1 ermitteln. So was

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

Sie können auch die veraltete Variable $ `verwenden, wenn Sie möchten, dass alle REs in Ihrem Programm langsamer ausgeführt werden. Von 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