Come posso trovare la prima occorrenza di un pattern in una stringa da una posizione iniziale?
Domanda
Ho una stringa di lunghezza arbitraria e, partendo dalla posizione p0, devo trovare la prima occorrenza di uno dei tre schemi di 3 lettere.
Supponiamo che la stringa contenga solo lettere. Devo trovare il conteggio delle terzine che iniziano nella posizione p0 e saltano avanti nelle terzine fino alla prima occorrenza di "aaa" o "bbb" o "ccc".
È anche possibile usare solo una regex?
Soluzione
Moritz dice che potrebbe essere più veloce di una regex. Anche se è un po 'più lento, è più facile da capire alle 5 del mattino. :)
#0123456789.123456789.123456789. my $string = "alsdhfaaasccclaaaagalkfgblkgbklfs"; my $pos = 9; my $length = 3; my $regex = qr/^(aaa|bbb|ccc)/; while( $pos < length $string ) { print "Checking $pos\n"; if( substr( $string, $pos, $length ) =~ /$regex/ ) { print "Found $1 at $pos\n"; last; } $pos += $length; }
Altri suggerimenti
$string=~/^ # from the start of the string
(?:.{$p0}) # skip (don't capture) "$p0" occurrences of any character
(?:...)*? # skip 3 characters at a time,
# as few times as possible (non-greedy)
(aaa|bbb|ccc) # capture aaa or bbb or ccc as $1
/x;
(Supponendo che p0 sia basato su 0).
Ovviamente, è probabilmente più efficiente usare substr sulla stringa per saltare in avanti:
substr($string, $p0)=~/^(?:...)*?(aaa|bbb|ccc)/;
Non puoi davvero contare sulle regex, ma puoi fare qualcosa del genere:
pos $string = $start_from;
$string =~ m/\G # anchor to previous pos()
((?:...)*?) # capture everything up to the match
(aaa|bbb|ccc)
/xs or die "No match"
my $result = length($1) / 3;
Ma penso che sia un po 'più veloce usare substr () e unpack () per dividere in triple e camminare le triple in un for-loop.
(modifica: è lunghezza (), non lunghezza () ;-)
La parte principale di questo è divisa /(...)/. Ma alla fine, avrai le tue posizioni e i dati di occorrenza.
my @expected_triplets = qw<aaa bbb ccc>;
my $data_string
= 'fjeidoaaaivtrxxcccfznaaauitbbbfzjasdjfncccftjtjqznnjgjaaajeitjgbbblafjan'
;
my $place = 0;
my @triplets = grep { length } split /(...)/, $data_string;
my %occurrence_for = map { La parte principale di questo è divisa /(...)/. Ma alla fine, avrai le tue posizioni e i dati di occorrenza.
my ( $count, %count );
my $data_string
= 'fjeidoaaaivtrxxcccfznaaauitbbbfzjasdjfncccftjtjqznnjgjaaajeitjgbbblafjan'
;
$data_string =~ m/(aaa|bbb|ccc)(??{ $count++; $count{$^N}++ })/g;
O per un semplice conteggio da regex (usa Experimental (?? {}))
<*>, [] } @expected_triplets;
foreach my $i ( 0..@triplets ) {
my $triplet = $triplets[$i];
push( @{$occurrence_for{$triplet}}, $i ) if exists $occurrence_for{$triplet};
}
O per un semplice conteggio da regex (usa Experimental (?? {}))
<*>Se la velocità è una preoccupazione seria, puoi, a seconda di cosa sono le 3 stringhe, diventare davvero fantasiosi creando un albero (ad esempio algoritmo Aho-Corasick o simile).
È possibile una mappa per ogni stato possibile, ad es. state [0] ['a'] = 0 se nessuna stringa inizia con 'a'.