JavaScript Regex Named Groups and Lookbehinds
JavaScript regular expressions provide advanced features to make pattern matching more readable and precise. This article explains how to implement named capture groups to extract data using custom labels instead of numerical indices, and how to use positive and negative lookbehind assertions to match text based on what precedes it without including those preceding characters in the result.
Named Capture Groups
Standard capture groups rely on numerical indices (e.g.,
result[1], result[2]), which can make code
fragile if the regular expression structure changes. Named capture
groups solve this by assigning explicit identifiers to matched
sub-patterns using the (?<name>pattern) syntax.
When a match is found, the captured values are accessible via the
groups property on the returned match object.
const datePattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = datePattern.exec('2026-03-30');
console.log(match.groups.year); // "2026"
console.log(match.groups.month); // "03"
console.log(match.groups.day); // "30"Using Named Groups in Replacement
Named groups can also be referenced directly in
String.prototype.replace() using the
$<name> syntax:
const dateString = '2026-03-30';
const formattedDate = dateString.replace(datePattern, '$<month>/$<day>/$<year>');
console.log(formattedDate); // "03/30/2026"Lookbehind Assertions
Lookbehind assertions determine whether a match is preceded by a specific pattern without consuming those characters as part of the match. There are two types: positive lookbehind and negative lookbehind.
Positive Lookbehind:
(?<=...)
A positive lookbehind ensures that the target pattern is immediately
preceded by the sub-pattern defined inside (?<=...).
// Match a price amount only if it is preceded by a dollar sign
const pricePattern = /(?<=\$)\d+(\.\d{2})?/;
const text = 'The total cost is $49.99 for the item.';
const result = text.match(pricePattern);
console.log(result[0]); // "49.99" (The '$' is not part of the match)Negative Lookbehind:
(?<!...)
A negative lookbehind ensures that the target pattern is
not immediately preceded by the sub-pattern defined
inside (?<!...).
// Match numbers that are NOT preceded by a dollar sign
const quantityPattern = /(?<!\$)\b\d+\b/g;
const inventoryText = 'Order 5 items for $50 each';
const numbers = inventoryText.match(quantityPattern);
console.log(numbers); // ["5"] (Ignores "50" because it follows "$")Combining Both Features
Named capture groups and lookbehind assertions can be combined to build clean, self-documenting parsing logic:
const logPattern = /(?<=ID:\s*)(?<userId>[A-Z0-9]+)/;
const logEntry = 'User logged in with ID: USR8821 at 10:00 AM';
const userMatch = logPattern.exec(logEntry);
if (userMatch) {
console.log(userMatch.groups.userId); // "USR8821"
}By leveraging named capture groups and lookbehind assertions, JavaScript regular expressions become more resilient to pattern modifications and easier to maintain across large codebases.