Lookbehind / Lookahead Regex in Vim - InputOutput.io

Lookbehind / Lookahead Regex in Vim

Here’s a nifty little vim tip for you.

I recently had to switch a few variables in PHP from $varname to $somearray['varname']. Since there were quite a few of these replacements to be done, I found it convenient to use vim’s search/replace regex feature. In this case, I have to use lookbehind, since the matching string is simply varname, and I’m not interested in catching the $ at the beginning. I just want the regex to match anything starting with the $, without having the $ as part of the matching string itself.

So, let’s try to replace the following line:

authenticate($key, $secret, $uri);

with this one:

authenticate($somearray['key'], $somearray['secret'], $somearray['uri']);

We’ll want to construct a lookbehind for the $, with some string in front. Then, we’ll replace it with $somearray['matching_string']. In vim, lookbehind uses the special @ symbol, rather than the perl (?<=somestring) syntax.

:’<,’>s/\$\@<=[a-z]\+/$somearray['&']/g

This will do the trick. As you can see, the $, @, and + must all be escaped. The lookbehind positive search chars, @<= can be replaced with @<! if a negative search is desired. Lookahead is similar to lookbehind's syntax, but uses @= and @! instead. The special & character in the replace string designates a matching token, which you can use to place the matching string in your replacement.

So for reference:

  • :%s/\(some\)\@<=thing/one/g
    

    searches for all strings starting with some, then matching thing
    changes thing into one

    end result: something becomes someone

  • :%s/\(some\)\@<!thing/one/g
    

    searches for all strings not starting with some, then matching thing
    changes thing into one

    end result: something is not changed, but everything changes to everyone

  • :%s/some\(thing\)\@=/every/g
    

    searches for all strings ending with thing, then matching some
    changes some into every

    end result: something becomes everything

  • :%s/some\(thing\)\@!/every/g
    

    searches for all strings not ending with thing, then matching some
    changes some into every

    end result: something is not changed, but someone becomes everyone

One Response to this post.

  1. Posted by TJ on 22.06.12 at 7:23 pm

    Thank you for this. A bit surprising that it’s this complicated (all the escapes and whatnot), but it worked just as intended.

Respond to this post