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





$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
/x;
(Предполагая, что p0 отсчитывается от 0).
Конечно, для перехода вперед, вероятно, более эффективно использовать substr в строке:
substr($string, $p0)=~/^(?:...)*?(aaa|bbb|ccc)/;
(пожалуйста, не обращайте внимания на мой комментарий выше) хороший, но мне нужно количество пропущенных троек - или, может быть, теперь, когда я знаю первый, я могу найти его pos и просто использовать разницу от p0 в качестве счетчика.
Нет, $ 1 будет содержать совпавший триплет (aaa, bbb или ccc). Но вы можете использовать $ - [1] для доступа к его начальной позиции.
Если вам нужно количество начальных троек, просто удалите?: Из парных скобок троек, чтобы они захватывались. Тогда длина ($ 1) / 3 - это количество пропущенных троек. Но ответ Брайана Д Фоя выглядит лучше ...
Вы не можете рассчитывать с помощью регулярных выражений, но вы можете сделать что-то вроде этого:
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() / 3;
Но я думаю, что немного быстрее использовать substr () и unpack () для разделения на тройки и обхода троек в цикле for.
(править: это length (), а не lenght () ;-)
Мориц говорит, что это может быть быстрее, чем регулярное выражение. Даже если он немного медленнее, в 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 at $pos\n";
last;
}
$pos += $length;
}
да, я должен написать KISS на плакате, наклеить его на стену над монитором! Спасибо.
Основная часть этого разделена /(...)/. Но в конце у вас будут данные о ваших позициях и происшествиях.
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};
}
Или для простого подсчета с помощью регулярного выражения (используется экспериментальный (?? {}))
my ( $count, %count );
my $data_string
= 'fjeidoaaaivtrxxcccfznaaauitbbbfzjasdjfncccftjtjqznnjgjaaajeitjgbbblafjan'
;
$data_string =~ m/(aaa|bbb|ccc)(??{ $count++; $count{$^N}++ })/g;
Если скорость вызывает серьезную озабоченность, вы можете, в зависимости от того, что это за 3 строки, по-настоящему фантазировать, создав дерево (например, алгоритм Aho-Corasick или аналогичный).
Возможна карта для каждого возможного состояния, например state [0] ['a'] = 0, если ни одна строка не начинается с 'a'.
будет ли $ 1 содержать количество троек?