JavaScript > Regular Expressions > RegExp Patterns > Lookahead and lookbehind

Lookahead and Lookbehind in JavaScript RegExp

Explore the power of lookahead and lookbehind assertions in JavaScript regular expressions. Learn how to match patterns based on what follows or precedes them without including those surrounding characters in the actual match. This allows for highly flexible and precise pattern matching.

Introduction to Lookahead and Lookbehind

Lookahead and lookbehind are powerful features in regular expressions that allow you to match patterns based on what comes before or after them, without including the lookahead/lookbehind part in the matched text. They're called 'assertions' because they assert that a certain pattern exists before or after the main pattern you're trying to match.

Positive Lookahead: Matching What Follows

(?=pattern) is the syntax for positive lookahead. It matches if the pattern is found after the main pattern. In this example, the regex /Java(?=Script)/ matches 'Java' only if it's followed by 'Script'. The 'Script' part itself isn't included in the matched result. The result will be the 'Java' string. If 'Java' isn't followed by 'Script', then there won't be a match.

const str = 'JavaScript is awesome!';
const regex = /Java(?=Script)/;
const match = str.match(regex);

console.log(match); // Output: ['Java', index: 0, input: 'JavaScript is awesome!', groups: undefined]

Negative Lookahead: Matching What Does Not Follow

(?!pattern) is the syntax for negative lookahead. It matches if the pattern is not found after the main pattern. In this example, the regex /Java(?!Script)/ matches 'Java' only if it's NOT followed by 'Script'. Therefore, this will find the 'Java' in the first 'Java' substring. If the string was just 'JavaScript', it would return null.

const str = 'Java is great, but JavaScript is better!';
const regex = /Java(?!Script)/;
const match = str.match(regex);

console.log(match); // Output: ['Java', index: 0, input: 'Java is great, but JavaScript is better!', groups: undefined]

Positive Lookbehind: Matching What Precedes (ES2018+)

(?<=pattern) is the syntax for positive lookbehind. It matches if the pattern is found before the main pattern. It was introduced in ES2018. In this example, the regex /(?<=USD )\d+/ matches one or more digits (\d+) only if they are preceded by 'USD '. The result includes only the digits, not 'USD '.

const str = 'USD 100, EUR 50';
const regex = /(?<=USD )\d+/;
const match = str.match(regex);

console.log(match); // Output: ['100', index: 4, input: 'USD 100, EUR 50', groups: undefined]

Negative Lookbehind: Matching What Does Not Precede (ES2018+)

(? is the syntax for negative lookbehind. It matches if the pattern is not found before the main pattern. It was introduced in ES2018. In this example, the regex /(? matches one or more digits (\d+) only if they are NOT preceded by 'USD '. Therefore, this will find the '50' string.

const str = 'USD 100, EUR 50';
const regex = /(?<!USD )\d+/;
const match = str.match(regex);

console.log(match); // Output: ['50', index: 17, input: 'USD 100, EUR 50', groups: undefined]

Real-Life Use Case: Validating Passwords

Lookaheads are extremely useful for validating password complexity. This example checks for uppercase letters, lowercase letters, numbers, special characters, and a minimum length, all using lookaheads. The multiple lookaheads allow you to assert all requirements are met without consuming the string. Each check does not move forward to the next character, but verifies a condition.

function validatePassword(password) {
  const hasUpperCase = /(?=.*[A-Z])/;
  const hasLowerCase = /(?=.*[a-z])/;
  const hasNumber = /(?=.*\d)/;
  const hasSpecialChar = /(?=.*[^a-zA-Z0-9\s])/;
  const isLongEnough = /^.{8,}$/;

  return (
    hasUpperCase.test(password) &&
    hasLowerCase.test(password) &&
    hasNumber.test(password) &&
    hasSpecialChar.test(password) &&
    isLongEnough.test(password)
  );
}

console.log(validatePassword('P@ssword123')); // Output: true
console.log(validatePassword('Password')); // Output: false

Best Practices

  • Keep it Simple: Complex regexes can be hard to read and debug. Break them down into smaller, more manageable parts if necessary.
  • Test Thoroughly: Ensure your regex works as expected with a variety of input strings, including edge cases.
  • Use Comments: For complex regexes, add comments to explain what each part does. While JavaScript doesn't support inline regex comments, you can break down the regex into variables and add comments around those.
  • Consider Performance: Overly complex lookarounds can impact performance. If performance is critical, explore alternative approaches.

When to Use Them

Use lookahead/lookbehind when you need to match a pattern based on its context (what's before or after it) without including the surrounding context in the match. This is particularly useful for validation, parsing, and complex text manipulation tasks.

Alternatives

While lookahead/lookbehind are powerful, sometimes you can achieve similar results with capturing groups and string manipulation. However, this often involves more code and can be less efficient, especially for complex patterns. You can also use multiple regular expressions combined to achieve the result.

Pros

  • Conciseness: They can express complex matching conditions in a compact way.
  • Flexibility: They provide a high degree of flexibility in pattern matching.
  • Readability (when used well): Well-crafted lookarounds can make your regex more readable by clearly expressing the matching intent.

Cons

  • Complexity: They can make regexes harder to understand, especially for beginners.
  • Performance: Complex lookarounds can impact performance, especially with large input strings.
  • Browser Compatibility: Lookbehind assertions are only supported in ES2018+ environments, so consider your target browsers.

FAQ

  • What's the difference between lookahead and lookbehind?

    Lookahead checks what's after the main pattern, while lookbehind checks what's before the main pattern. Both are assertions that don't include the matched surrounding text in the final result.
  • Are lookbehind assertions supported in all browsers?

    No, lookbehind assertions were introduced in ES2018 and may not be supported in older browsers. Always check browser compatibility before using them in production.
  • Can I use lookaheads and lookbehinds together in the same regular expression?

    Yes, you can combine lookaheads and lookbehinds to create very specific and powerful matching conditions. However, ensure the complexity doesn't impact readability or performance.