What are lookahead and lookbehind assertions, and how do they work?

Let’s learn about lookahead and lookbehind assertions in regular expressions.

Lookahead and lookbehind assertions allow you to match specific patterns based on the presence or lack of surrounding patterns. There are four variations of these assertions.

First is the positive lookahead assertion. This assertion will match a pattern when the pattern is followed by another pattern.

To construct a positive lookahead, you need to start with the pattern you want to match. Then, use parentheses to wrap the pattern you want to use as your condition. After the opening parenthesis, use ?= to define that pattern as a positive lookahead.

This pattern will only match the word free if it is followed by code:

const regex = /free(?=code)/i;

Let’s test the behavior of our pattern:

const regex = /free(?=code)/i;
console.log(regex.test("freeCodeCamp")); // true
console.log(regex.test("free code camp")); // false
console.log(
  regex.test("I need someone for free to write code for me")
); // false

Notice how only the string where free is immediately followed by code passes the test.

But what if you want to match the presence of free when it is NOT followed by code? You can turn your positive lookahead into a negative lookahead to invert the behavior. To do this, change your ?= to ?!:

const regex = /free(?!code)/i;

Let’s test this against our same strings:

const regex = /free(?!code)/i;
console.log(regex.test("freeCodeCamp")); // false
console.log(regex.test("free code camp")); // true
console.log(
  regex.test("I need someone for free to write code for me")
); // true

As expected, the results are reversed. The only string that fails is the first string, where free is immediately followed by code.

Lookbehind assertions function similarly to lookahead assertions, except that, instead of matching conditionally based on a following pattern, they match conditionally based on a preceding pattern. Let’s take a look at a positive lookbehind.

A positive lookbehind is denoted with ?<= instead of ?=. Let’s make our regular expression match code when it is preceded by free:

const regex = /(?<=free)code/i;

Just like with our positive lookahead, our positive lookbehind matches the first string because code is immediately preceded by free:

const regex = /(?<=free)code/i;
console.log(regex.test("freeCodeCamp")); // true
console.log(regex.test("free code camp")); // false
console.log(
  regex.test("I need someone for free to write code for me")
); // false

To match code when it is NOT preceded by free, we can use a negative lookbehind. A negative lookbehind is defined by replacing ?<= with ?<!:

const regex = /(?<!free)code/i;

This would match any occurrence of code that is NOT immediately preceded by free.

const regex = /(?<!free)code/i;
console.log(regex.test("freeCodeCamp")); // false
console.log(regex.test("free code camp")); // true
console.log(
  regex.test("I need someone for free to write code for me")
); // true

Remember that Regex.prototype.test only confirms whether a string matches the regular expression. Let’s use our negative lookbehind with String.prototype.match to see how assertions affect that:

const regex = /(?<!free)code/i;
console.log("freeCodeCamp".match(regex)); // null
console.log("free code camp".match(regex)); // ['code', index: 5, input: 'free code camp', groups: undefined]
console.log(
  "I need someone for free to write code for me".match(regex)
); // ['code', index: 33, input: 'I need someone for free to write code for me', groups: undefined]

Notice how even though our regular expression uses a lookbehind to check for the presence of free, it does not match free. The only text included in the match is code.

Lookaheads and lookbehinds are incredibly useful for conditionally matching text without impacting the returned value of your match.