If you want to search for a pattern only when it occurs next to another pattern, use the regex features “lookahead” and “lookbehind” (collectively “lookaround”). If you want to search for a pattern only when it doesn't occur next to another, use their complements, “negative lookahead” and “negative lookbehind” (“negative lookaround”).
Match start and end[]
The simplest and most performant way to do positive lookaround in most cases is to mark the start and/or end of your match with \zs
and \ze
. The parts of the pattern before the \zs
and/or after the \ze
match with zero length. In other words, they must be found in the text in order to make a match, but will not be included in the match. That means they won't be substituted or highlighted.
Examples[]
foo \zsbar\ze baz
matches the “bar” infoo bar baz
. But the whole pattern is still required, so it doesn't match at all forfoo bar qux
orfoo bar
orfoo
.
You can use one or the other alone:
mi \zscasa
matches “casa” if preceded by “mi ”. So it matches only the first “casa” inmi casa es su casa
.dad\ze.
matches “dad” if followed by a period. So it matches only the second “dad” inMy dad is bigger than your dad.
Help[]
Classic lookaround[]
If you're familiar with PCRE or other regex engines, you may prefer lookahead and lookbehind assertions. Negative lookaround is also the only way to assert that a certain pattern is not present.
The following strings with @
are assertions that the preceding atom (which may be a group) does or does not exist just ahead or behind the current position in the pattern. The atom (or its absence) will match with zero length.
lookbehind | lookahead | |
---|---|---|
positive | \(atom\)\@<=
|
\(atom\)\@=
|
negative | \(atom\)\@<!
|
\(atom\)\@!
|
In very magic mode:
lookbehind | lookahead | |
---|---|---|
positive | (atom)@<=
|
(atom)@=
|
negative | (atom)@<!
|
(atom)@!
|
Examples[]
\(foo \)\@<=bar\( baz\)\@=
matches the “bar” infoo bar baz
. But the lookaround groups are still required, so it doesn't match at all forfoo bar qux
orfoo bar
orfoo
.(foo )@<=bar( baz)@=
in very magic mode.
\(mi \)\@<=casa
matches “casa” if preceded by “mi ”. So it matches only the first “casa” inmi casa es su casa
.\(mi \)\@<!casa
matches “casa” if not preceded by “mi ”. So it matches only the second “casa” inmi casa es su casa
.dad.\@=
matches “dad” if followed by a period. So it matches only the second “dad” inMy dad is bigger than your dad.
dad.\@!
matches “dad” if not followed by a period. So it matches only the first “dad” inMy dad is bigger than your dad.
Help[]
External links[]
- Lookahead & Lookbehind on Regular-Expressions.info
- Lookaround, part 2 on Regular-Expressions.info
- Positive/Negative Lookahead/Lookbehind in Vim on jbodah.github.io