Lesson guide

Learning objectives

  • Explain the main purpose of Lookahead and lookbehind in JavaScript.
  • Identify the syntax, APIs, or concepts introduced in this lesson.
  • Use the examples to predict how JavaScript will behave before you run similar code.
  • Connect this topic to nearby lessons in Regular expressions.

Real-world context

This lesson matters when you need to recognize where Lookahead and lookbehind fits into real JavaScript programs. Sometimes we need to find only those matches for a pattern that are followed or preceded by another pattern.

Key ideas

  • Lookahead and lookbehind is part of the Regular expressions chapter, so it builds on the surrounding concepts rather than standing alone.
  • Read each code example in two passes: first for the result, then for the rule that explains the result.
  • When a section compares similar features, focus on the condition that makes you choose one feature over another.

Key terms

  • Lookahead and lookbehind
  • Lookahead
  • lookbehind
  • Regular expressions
  • JavaScript

Sometimes we need to find only those matches for a pattern that are followed or preceded by another pattern.

There’s a special syntax for that, called “lookahead” and “lookbehind”, together referred to as “lookaround”.

For the start, let’s find the price from the string like 1 turkey costs 30€. That is: a number, followed by sign.

Lookahead

The syntax is: X(?=Y), it means “look for X, but match only if followed by Y”. There may be any pattern instead of X and Y.

For an integer number followed by , the regexp will be \d+(?=€):

javascript
let str = "1 turkey costs 30€";

alert( str.match(/\d+(?=)/) ); // 30, the number 1 is ignored, as it's not followed by €

Please note: the lookahead is merely a test, the contents of the parentheses (?=...) is not included in the result 30.

When we look for X(?=Y), the regular expression engine finds X and then checks if there’s Y immediately after it. If it’s not so, then the potential match is skipped, and the search continues.

More complex tests are possible, e.g. X(?=Y)(?=Z) means:

  1. Find X.
  2. Check if Y is immediately after X (skip if isn’t).
  3. Check if Z is also immediately after X (skip if isn’t).
  4. If both tests passed, then the X is a match, otherwise continue searching.

In other words, such pattern means that we’re looking for X followed by Y and Z at the same time.

That’s only possible if patterns Y and Z aren’t mutually exclusive.

For example, \d+(?=\s)(?=.*30) looks for \d+ that is followed by a space (?=\s), and there’s 30 somewhere after it (?=.*30):

javascript
let str = "1 turkey costs 30€";

alert( str.match(/\d+(?=\s)(?=.*30)/) ); // 1

In our string that exactly matches the number 1.

Negative lookahead

Let’s say that we want a quantity instead, not a price from the same string. That’s a number \d+, NOT followed by .

For that, a negative lookahead can be applied.

The syntax is: X(?!Y), it means “search X, but only if not followed by Y”.

javascript
let str = "2 turkeys cost 60€";

alert( str.match(/\d+\b(?!)/g) ); // 2 (the price is not matched)

Lookbehind

Lookbehind browser compatibility

Please Note: Lookbehind is not supported in non-V8 browsers, such as Safari, Internet Explorer.

Lookahead allows to add a condition for “what follows”.

Lookbehind is similar, but it looks behind. That is, it allows to match a pattern only if there’s something before it.

The syntax is:

  • Positive lookbehind: (?<=Y)X, matches X, but only if there’s Y before it.
  • Negative lookbehind: (?<!Y)X, matches X, but only if there’s no Y before it.

For example, let’s change the price to US dollars. The dollar sign is usually before the number, so to look for $30 we’ll use (?<=\$)\d+ – an amount preceded by $:

javascript
let str = "1 turkey costs $30";

// the dollar sign is escaped \$
alert( str.match(/(?<=\$)\d+/) ); // 30 (skipped the sole number)

And, if we need the quantity – a number, not preceded by $, then we can use a negative lookbehind (?<!\$)\d+:

javascript
let str = "2 turkeys cost $60";

alert( str.match(/(?<!\$)\b\d+/g) ); // 2 (the price is not matched)

Capturing groups

Generally, the contents inside lookaround parentheses does not become a part of the result.

E.g. in the pattern \d+(?=€), the sign doesn’t get captured as a part of the match. That’s natural: we look for a number \d+, while (?=€) is just a test that it should be followed by .

But in some situations we might want to capture the lookaround expression as well, or a part of it. That’s possible. Just wrap that part into additional parentheses.

In the example below the currency sign (€|kr) is captured, along with the amount:

javascript
let str = "1 turkey costs 30€";
let regexp = /\d+(?=(|kr))/; // extra parentheses around €|kr

alert( str.match(regexp) ); // 30, €

And here’s the same for lookbehind:

javascript
let str = "1 turkey costs $30";
let regexp = /(?<=(\$|£))\d+/;

alert( str.match(regexp) ); // 30, $

Common mistakes

  • Skipping the small examples and then missing the exact rule that Lookahead and lookbehind depends on.
  • Copying code without changing one value at a time to see which part controls the result.
  • Treating similar-looking syntax or APIs as interchangeable before checking their edge cases.

Summary

Lookahead and lookbehind (commonly referred to as “lookaround”) are useful when we’d like to match something depending on the context before/after it.

For simple regexps we can do the similar thing manually. That is: match everything, in any context, and then filter by context in the loop.

Remember, str.match (without flag g) and str.matchAll (always) return matches as arrays with index property, so we know where exactly in the text it is, and can check the context.

But generally lookaround is more convenient.

Lookaround types:

Patterntypematches
X(?=Y)Positive lookaheadX if followed by Y
X(?!Y)Negative lookaheadX if not followed by Y
(?<=Y)XPositive lookbehindX if after Y
(?<!Y)XNegative lookbehindX if not after Y

Predict

Before running this lookaround block, predict the six output lines. It shows positive and negative lookahead, positive and negative lookbehind, and the special case where an inner group inside lookaround is still captured.

javascript
Reveal explanation

Lookaround checks context without including that context in the main match. \d+(?=€) returns 30, not 30€; (?<=\$)\d+ returns 60, not $60. Negative lookaround does the inverse, keeping the quantity while skipping prices. If a capturing group is placed inside the lookaround, that inner group is still available in the result array.

Try it

Change 30€ to 30kr, then predict which lookahead pattern still matches. Then remove the backslash before $ in the lookbehind and explain why $ stops meaning a literal dollar sign.

Practice

  • Rewrite one example from this lesson without looking at the original, then run it and compare the result.
  • Change one input, operator, method call, or option in a code sample and predict what will happen before running it.
  • Explain Lookahead and lookbehind in your own words as if you were reviewing it with another learner.

Keep learning

Continue with Catastrophic backtracking when you are ready for the next lesson.