Как найти первое появление шаблона в строке из некоторой начальной позиции?

StackOverflow https://stackoverflow.com/questions/120071

  •  02-07-2019
  •  | 
  •  

Вопрос

У меня есть строка произвольной длины, и, начиная с позиции p0, мне нужно найти первое вхождение одного из трех трехбуквенных шаблонов.

Предположим, что строка содержит только буквы.Мне нужно найти количество троек, начиная с позиции p0 и переходя вперед по тройкам до первого появления «aaa», «bbb» или «ccc».

Возможно ли это вообще, используя только регулярное выражение?

Это было полезно?

Решение

Мориц говорит, что это может быть быстрее, чем регулярное выражение.Даже если немного медленнее, в 5 утра это легче понять.:)

             #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;
    }

Другие советы

$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;

(Предполагая, что p0 основан на 0).

Конечно, для перехода вперед, вероятно, более эффективно использовать substr в строке:

substr($string, $p0)=~/^(?:...)*?(aaa|bbb|ccc)/;

Вы не можете считать с помощью регулярных выражений, но вы можете сделать что-то вроде этого:

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;

Но я думаю, что немного быстрее использовать substr() и unpack() для разделения на тройки и обхода троек в цикле for.

(редактировать:это length(), а не length() ;-)

Основная часть этого разделена /(...)/.Но в конце вы получите данные о своих позициях и событиях.

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 { $_, [] } @expected_triplets;
foreach my $i ( 0..@triplets ) {
    my $triplet = $triplets[$i];
    push( @{$occurrence_for{$triplet}}, $i ) if exists $occurrence_for{$triplet};
}

Или для простого подсчета по регулярному выражению (используется Experimental (??{}))

my ( $count, %count );
my $data_string      
    = 'fjeidoaaaivtrxxcccfznaaauitbbbfzjasdjfncccftjtjqznnjgjaaajeitjgbbblafjan'
    ;
$data_string =~ m/(aaa|bbb|ccc)(??{ $count++; $count{$^N}++ })/g;

Если скорость вызывает серьезную озабоченность, вы можете, в зависимости от того, какие три строки представляют собой, по-настоящему пофантазировать, создав дерево (например,Алгоритм Ахо-Корасика или аналогичный).

Возможна карта для каждого возможного состояния, например.state[0]['a'] = 0, если ни одна строка не начинается с 'a'.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top