From time to time, the need to match things not preceded by a pattern rears its head, and the natural tool for that is negative lookbehind. But if the pattern is variable-length, Perl's regex engine can't handle it. This limitation has, at times, resulted in bruised foreheads.
Here are a couple of recipes for working around that limitation. They're not pretty, but they should be plug-and-play.
You define variables for what you want and what you don't want to precede it, and just use the pattern as it appears above.# capture all two\d that are not preceded by fo+ $_ = 'footwo1 bootwo2 ftwo3 fotwo4'; $not = qr/fo+/; $want = qr/two\d/; print "Got $1\n" while /\G(?:(?!$not?$want).|$not$want)*($want)/g;
Or you can match and substitute separately:s/\G((?:(?!$not?$want).|$not$want)*)($want)/$1X/g;
If you want to do a single, rather than global replacement, change the while to an if. Leave the /g on the match -- it is necessary for setting the \G marker.s/\G$want/X/ while /\G(?:(?!$not?$want).|$not$want)*(?=$want)/g;
Note: Regexp::Keep would be very handy here, but this blew up for me:
s/\G((?:(?!$not?$want).|$not$want)*)\K($want)/X/g; # yielded Eval-group not allowed at runtime, use re 'eval' in regex m/\G((?:(?!( +?-xism:fo+)?(?-xism:two\d)).|(?-xism:fo+)(?-xism:two\d))*)(?{Regexp:: +Keep::KEEP})((?-xism:two\d))/ at try2.pl line 9.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Variable-length negative lookbehind
by kvale (Monsignor) on May 07, 2004 at 16:54 UTC | |
by Roy Johnson (Monsignor) on May 07, 2004 at 17:22 UTC | |
|
Re: Variable-length negative lookbehind
by flyingmoose (Priest) on May 07, 2004 at 17:35 UTC | |
|
Re: Variable-length negative lookbehind
by japhy (Canon) on May 07, 2004 at 20:17 UTC | |
|
Re: Variable-length negative lookbehind
by dragonchild (Archbishop) on May 07, 2004 at 17:05 UTC | |
by Roy Johnson (Monsignor) on May 07, 2004 at 18:47 UTC |