21

I have encountered many situations in vim where it would be useful to have lookaround statements. I have tried using the standard lookaround syntax ((?=), (?!) etc ..), but it appears vim does not support this. Does vim have an equivalent syntax for these kinds of statements?

29

"Zoom" anchors

In addition to @jecxjo's answer, there are many situations where you can use the zero-width anchors \zs and \ze instead of positive lookaround. These anchors define the start (\zs) and the end (\ze) of the match within the full pattern.

Examples

  • foo\zsbar will match bar preceded by foo (foo not part of the match)
  • foo\zebar will match foo followed by bar (bar not part of the match)
  • myFunction(\zs.*\ze) will match the parameters in a function call (for demonstration purposes, I'm not focusing on greedy vs non-greedy matching)

Putting it to use

These become most useful when using the :substitute command. For example, say I wanted to replace the parameters in a function call to myFunction() with foo:

:%s/myFunction(\zs.*\ze)/foo/

This will leave myFunction( and ) intact, and you don't have to worry about capturing them in your pattern or repeating them in your replacement.

You could do this using the lookaround feature of Vim's regex, but it's quite clunky:

:%s/\(myFunction(\)\@<=.*\()\)\@=/foo/

(I find this syntax causes me to forget what I was trying to do in the first place.)

You still need lookaround sometimes

There are still situations where you need lookaround. Using \zs and \ze are great for simple situations where you have something before followed by text to match followed by something after. But if it's more complex than that, you'll probably have to stick to the heavier lookaround syntax.

Fun fact

Though they're considerably uglier, Vim's lookarounds are more powerful than those in PCRE! They support variable-length negative lookbehind, meaning you can assert that some pattern whose length is not predetermined is not before your match.

PCRE doesn't support this, as it's fairly computationally expensive. That's not a huge concern in Vim, since the most common use cases of regex tend to involve interactive searching where the computation time is nearly imperceptible to the user. You'd probably notice it if it were used for syntax highlighting, though.

Relevant Help Topics

  • :help \zs
  • :help \ze
  • :help perl-patterns
  • I was not aware of the zoom anchors. Thanks for explaining them. – EvergreenTree Apr 22 '15 at 21:21
13

It looks as if this is possible. There is a simple table to go from perl to vim. :h perl-patterns

9. Compare with Perl patterns               *perl-patterns*

Vim's regexes are most similar to Perl's, in terms of what you can do.  The
difference between them is mostly just notation;  here's a summary of where
they differ:

Capability                  in Vimspeak   in Perlspeak
----------------------------------------------------------------
force case insensitivity    \c            (?i)
force case sensitivity      \C            (?-i)
backref-less grouping       \%(atom\)     (?:atom)
conservative quantifiers    \{-n,m}       *?, +?, ??, {}?
0-width match               atom\@=       (?=atom)
0-width non-match           atom\@!       (?!atom)
0-width preceding match     atom\@<=      (?<=atom)
0-width preceding non-match atom\@<!      (?<!atom)
match without retry         atom\@>       (?>atom)

So for example if you have the string one two three and you want to match for one only if <space>two follows it you can use

/one\(\stwo\)\@=

This is similar to the perl version

m/one(?=\stwo)/

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.