РЕДАКТИРОВАТЬ: После еще немного возни и думал, что я нашел правильное решение, я оставлю предыдущий ответ для справки ...
Кажется, /aaaa(?!aaaa)....|(?!aaaa)..../gc является дополнением / aaaa / для ваших целей:
$_ = 'aaaaabaaabaaabacaaaa';
while( /aaaa(?!aaaa)....|(?!aaaa)..../gc ){
my $b_pos = (pos()/4)-1;
print substr($_,$b_pos*4,4)." at :$b_pos\n";
}
Дает в результате:
abaa at :1
abaa at :2
abac at :3
Предыдущий ответ
Отрицательный взгляд не взаимодействует с итерацией «блока», даже при вводе небольших выборок:
use POSIX floor;
$_ = 'aaaaabaaabaaabacaaaa';
while( /(?!aaaa)..../gc ){
my $b_pos = floor(pos()/4);
print " !aaaa at :$b_pos str:".substr($_,$b_pos*4,4);
print " c_pos:".(pos()-4)." str:".substr($_,(pos()-4),4)."\n";
}
С выводом:
!aaaa at :1 str:abaa c_pos:2 str:aaab
!aaaa at :2 str:abaa c_pos:6 str:aaab
!aaaa at :3 str:abac c_pos:10 str:aaab
!aaaa at :4 str:aaaa c_pos:14 str:acaa
Это потому, что предвидение будет оцениваться символ за символом, а не в блоках по 4. Это означает, что в случае с aaaabaaa, он будет проверять aaaa, а затем aaab, который не будет совпадать с aaaa, таким образом, они будут использованы, а не baaa как можно было бы хотеть ...
Однако разумное использование map, grep и split решает проблему:
my $c = 0;
print "!aaaa at positions: ",
join ",", map { $$_[1] }
grep { $$_[0] !~ /aaaa/ }
map { [$_, $c++ ] }
grep /./, split /(.{4})/, $_;
print "\n";
Результат:
!aaaa at positions: 1,2,3
Пояснение:
- split /(.width4goti)/, $ _ разделит ввод на список блоков из 4 символов
- Однако использование захвата регулярных выражений в split может привести к тому, что пустые блоки будут в списке, поэтому мы исключаем их, используя grep /./
- Теперь мы создадим кортежи входных данных плюс номер блока (таким образом, нам нужен $ c, инициализированный в 0 ...)
- Теперь мы фильтруем элементы, которые не соответствуют 'aaaa'
- Теперь мы сопоставляем, чтобы получить только номер блока ...
Для соответствия точному выводу:
my $c = 0;
print "",
join "\n",
map { $$_[0]." at: ".$$_[1] }
grep { $$_[0] !~ /aaaa/ }
map { [$_, $c++ ] }
grep /./, split /(.{4})/, $_;
print "\n";