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?
2 Answers
"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 matchbar
preceded byfoo
(foo
not part of the match)foo\zebar
will matchfoo
followed bybar
(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. Apr 22, 2015 at 21:21
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)/