skip to content
blog.metters.dev

Positive and negative lookaround

/ 3 min read

Given the situation that you have to replace a specific term in your code base, but e.g. only those that are not preceded by a particular term. How would you search for those? One way is manually picking the matches that have to be replaced. Another way would be using regular expression and its negative lookbehind. With the help of regular expressions and lookaround it is possible to exclude patterns before and after a math or require the presence of a pattern.

Lookbehind

As already stated, with the help of lookbehind, the search looks at what is before the search term (as viewed from ltr languages).

Negative lookbehind

It is easier to memorize this as follows: The search looks back at what already has been processed. In case of a negative lookbehind, matches are excluded.

For example, (?<!hello)world matches all occurrences of “world” that are not preceded by a “hello”.

Negative lookbehind
(?<!hello)world
helloworld! fooworld! hello world! hello, world!

Positive lookbehind

Instead of excluding matches that are preceded by a defined term, it is also possible to exclude all other matches. This comes in handy if one wants to replace only part of the matches, without using groups in both, the search and the replacement expressions.

(?<=hello)world matches all world that are preceded by a “hello”. Note that only the “world” in “helloworld” is matched. Using groups to replace “world” with “John” the search expression would have to be (hello)(world) with a replacement expression $1John

Positive lookbehind
(?<=hello)world
helloworld! fooworld! hello world! hello, world!

Lookahead

A lookahead search expression looks at what is after the search term.

Negative lookahead

hello(?!world) matches a “hello” not followed by a “world”.

Negative lookahead
hello(?!world)
helloworld! fooworld! hello world! hello, world!

Positive lookahead

hello(?=world) matches a “hello” immediately followed by a “world”.

Positive lookahead
hello(?=world)
helloworld! fooworld! hello world! hello, world!

A lesson learnt

While I was writing this, I actually didn’t think that a positive lookbehind would be a thing. Why would this be useful? The pattern of the positive lookbehind is matched, but without being marked as result. This could save some time of having to use a group to exclude the first or last part (or middle part) of a match in find and replace scenarios.

Searching (?<=hello )world and replacing with John is much faster and easier to comprehend, than searching for (hello )(world) and replacing the matches with $1John. This is just a simplified example, but working with groups can become quite messy.

Further resources and references

Most of the following text is better described here, I just extracted a few key points that interest me from there and adapt the examples to my own needs. I highly recommend to also check out those two sites: