Update:
I thought about this a little more and came up with this solution using the built-in code block, which is almost three times faster than the grep solution:
use 5.010; use warnings; use strict; {my @pos; my $push_pos = qr/(?{push @pos, $-[0]})/; sub with_code { my ($re, $str) = @_; @pos = (); $str =~ /(?:$re)$push_pos(?!)/; @pos }}
and for comparison:
sub with_grep {
Tested and verified with:
use Benchmark 'cmpthese'; my @arg = qw(aa aaaabbbbbbbaaabbbbbaaa); my $expect = 7; for my $sub qw(grep while code look_ahead) { no strict 'refs'; my @got = &{"with_$sub"}(@arg); "@got" eq '0 1 2 11 12 19 20' or die "$sub: @got"; } cmpthese -2 => { grep => sub {with_grep (@arg) == $expect or die}, while => sub {with_while (@arg) == $expect or die}, code => sub {with_code (@arg) == $expect or die}, ahead => sub {with_look_ahead(@arg) == $expect or die}, };
What prints:
Rate grep while ahead code grep 49337/s -- -20% -43% -65% while 61293/s 24% -- -29% -56% ahead 86340/s 75% 41% -- -38% code 139161/s 182% 127% 61% --
source share