in reply to look-behind regex

While Tom Christiansen was working on the Cookbook, he and I were once musing how to write a regex that matches strings that doesn't contain a certain pattern. We came up with:
/^(?:(?!pattern).)*$/s;
which is pretty straight forward if you realize how regular expressions are matched.

For your problem, this leads to:

s/^((?:(?!toto).)*?)foo/${1}bar/s;
And if Japhy's new \K assertions gets accepted, you will be able to write it as:
s/^((?:(?!toto).)*?)\Kfoo/bar/s;
Abigail

Replies are listed 'Best First'.
Re: Re: look-behind regex
by japhy (Canon) on Jul 24, 2002 at 12:55 UTC
    The problem I have with /(?:(?!foo).)*/ is its slowness. Update: I'm wrong. Apparently, this method is usually the fastest.

    _____________________________________________________
    Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a job (NYC-area)
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

      In this particular case there's possibly a faster method though:

      s/^(?!(?>.*?toto.*?foo))(.*?)foo/${1}bar/s;

      If toto or foo can be found in the near beginning, Abigail's pattern is a winner. This is, I guess, due to the overhead of the (?>) assertion. But the farther away toto or foo is the worse it gets for the step-by-step method (/(?:(?!foo).)*/), and the (?>) pattern gets faster. (This isn't just a theoretical win. Even though the overhead due to (?>), that pattern might very well win in a real-life situation.)

      But if I shall look at the big picture for a while though; in this case I find it hard to believe that any pattern can beat the plain and simple

      s/foo/bar/ unless /toto.*?foo/s;

      Even silly constructions like

      s/foo(?(?{index($`, 'toto') != -1})(?!))/bar/;

      is faster than the more generic solutions.

      Cheers,
      -Anomo