it-swarm.it

Come posso trovare la posizione di una corrispondenza regolare in Perl?

Devo scrivere una funzione che riceva una stringa e una regex. Devo controllare se c'è una corrispondenza e restituire la posizione iniziale e finale di una partita. (Il regex è stato già compilato da qr//.)

La funzione potrebbe anche ricevere un flag "globale" e quindi ho bisogno di restituire le coppie (inizio, fine) di tutte le partite.

Non riesco a modificare la regex, nemmeno aggiungere () attorno ad esso come l'utente potrebbe utilizzare () e \1. Forse posso usare (?:).

Esempio: dato "ababab" e regex qr/ab/, nel caso globale devo recuperare 3 coppie di (inizio, fine).

32
szabgab

Le variabili integrate @- e @+ mantengono le posizioni di inizio e fine, rispettivamente, dell'ultima corrispondenza andata a buon fine. $-[0] e $+[0] corrispondono all'intero pattern, mentre $-[N] e $+[N] corrispondono alle submatch $N ($1, $2, ecc.).

72
Michael Carman

Dimentica il mio post precedente, ho un'idea migliore.

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
}

Questa tecnica non modifica in alcun modo la regex.

Modificato per aggiungere: per citare da perlvar su $ 1 .. $ 9. "Queste variabili sono tutte di sola lettura e con ambito dinamico per il BLOCCO corrente." In altre parole, se si desidera utilizzare $ 1 .. $ 9, non è possibile utilizzare una subroutine per eseguire la corrispondenza.

19
Leon Timmermans

La funzione pos ti dà la posizione della partita. Se metti la tua espressione regolare tra parentesi, puoi ottenere la lunghezza (e quindi la fine) usando length $1. Come questo

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

Puoi anche usare la variabile $ `deprecata, se sei disposto a far rallentare tutti i RE nel tuo programma. Da 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