http://www.perlmonks.org?node_id=412806


in reply to Count multiple pattern matches

One way is almost what you have, but with some changes,

use strict; my (@keywords, %keyword)=qw/foo bar 12345 abcd/; my ($string, %result) = "foobarfoo1234523423412345abcdefsadfabc";
Precompile the regexen, @keyword{@keywords} =  map {qr/\Q$_\E/} @keywords;
Now get the count directly without any named temporary,
$result{$_} = () = $string =~ $keyword{$_} for (keys %keyword);
That's no big change over what you have, but uses some idiomatic optimizations.

Another way is to count within the big regex you mention. You can do that with a code construction in the re,

my @regexen = map { qr/(?:\Q$_\E(?{$result{$_}++}))/ } @keywords; my $re = do { local $" = '|'; qr/@regexen/; };
I've used my favorite tricky way of getting alternation into an array there (qr// is an interpolating quote operator).
$string =~ /$re/g; print "$_: $result{$_}\n" for @keywords;
There, the regex engine should only evaluate the code part if the text has matched, and then restart the regex at pos for the next match. Untested,

Update: Perl qr// dosn't seem to like running the (?{$result{$_}++}) bit. I'm not sure why. Anybody know?

A third way is to munch through the string with index for each word you want to match.

It may be worthwhile to study your text before running the regex matches on it. Benchmark your different approaches, chances are that each will be best for some cases.

After Compline,
Zaxo