I don't want to run down Regexp::Keep, because I think it's nifty. But I do want to point out a few things:
- It doesn't provide any help with variable-width negative lookbehind (which the OP thought was needed)
- Depending on the regexp, it can be faster or slower than the two-regexp method.
- It's slightly broken (see below)
Here's some benchmarking code:
use Benchmark 'cmpthese';
use strict;
use Regexp::Keep;
my @strings = ('one two three four', 'two three four five', 'one three
+ five');
my @copy;
sub replace { s/(o+ )three/$1/ for @copy=@strings }
sub keep { s/o+ \Kthree// for @copy=@strings }
sub two { /o+ (?=three)/g and s/\Gthree// for @copy=@strings }
cmpthese(-3, {
'replace' => \&replace,
'keep' => \&keep,
'two' => \&two
});
replace;
print "Replace: ", join("\n", @copy), "\n";
keep;
print "Keep: ", join("\n", @copy), "\n";
two;
print "Two: ", join("\n", @copy), "\n";
As written, I got these results:
Rate replace keep two
replace 4739/s -- -15% -26%
keep 5587/s 18% -- -13%
two 6386/s 35% 14% --
Replace: one two four
two four five
one three five
Keep: one two four
two four five
one three five
Two: one two four
two four five
one three five
Note that keep yields different output: it doesn't keep the space. If I move the \K to follow the "t" in "three" (or anywhere in "three" -- even at the end of the pattern!), it doesn't affect the output.
If I change the o+ to an e+, keep wins by a hair. If I change it to an r (so that nothing matches or is substituted), replace wins and two loses.
The lookahead is necessary for non-global replacement. For global, the subs can look like this:
sub replace { s/(o+ )three/$1/g for @copy=@strings }
sub keep { s/o+ \Kthree//g for @copy=@strings }
sub two { do {s/\Gthree// while /o+ /g} for @copy=@strings }
and, in addition to being much neater, keep wins by a hair.
Update:Interestingly, this one-match alternative is significantly slower -- about a third slower than replace.
sub two { /o+ (?=(three))/g and substr($_, $-[1], $+[1]-$-[1], '')
+ for @copy=@strings
The PerlMonk tr/// Advocate
|