Code of the Day
IntermediateGroups and references

Named groups

Assign readable names to capturing groups with (?<name>…) so match results can be accessed by name instead of position.

Regular ExpressionsIntermediate8 min read
Recommended first
By the end of this lesson you will be able to:
  • Write a named capturing group using (?<name>…) syntax
  • Access a named group's value from the match result
  • Explain when named groups are preferable to numbered groups

When a pattern has more than two or three groups, positional indices become a maintenance burden. Renaming the pattern later means renumbering everything that reads from it. Named groups solve this by letting you attach a label directly to each group.

Syntax

Use (?<name>…) — a question mark, angle brackets around the name, then the pattern:

const m = "2024-03-15".match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/);

// Positional (still works)
console.log(m[1]);  // "2024"

// By name — via the match object's groups property
console.log(m.groups.year);   // "2024"
console.log(m.groups.month);  // "03"
console.log(m.groups.day);    // "15"

The groups property of the match result is a plain object containing all named groups. Unnamed groups do not appear in groups.

Destructuring named groups

You can destructure directly from m.groups:

const { year, month, day } = "2024-03-15".match(
  /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
).groups;

console.log(year, month, day); // "2024" "03" "15"

This is the cleanest way to consume a named-group match in modern JavaScript.

Named groups in Python

Python uses the same (?P<name>…) syntax (note the P — a historical quirk):

import re
m = re.search(r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})", "2024-03-15")
m.group("year")   # "2024"
m.group("month")  # "03"
m.groupdict()     # {"year": "2024", "month": "03", "day": "15"}

JavaScript added (?<name>…) syntax in ES2018. Python's (?P<name>…) has been available since Python 2.7. The meaning is the same; only the delimiter differs.

When to use named groups

Use named groups when:

  • The pattern has three or more capturing groups
  • The groups are reused in multiple places in your codebase
  • The pattern may change and you want the call sites to stay stable
  • You are writing code that will be read (and maintained) by someone else

Numbered groups are fine for short, one-off patterns. Once a pattern grows or is used in multiple places, names pay dividends quickly.

Named groups with matchAll

Named groups work with matchAll the same way they work with match:

const re = /(?<host>[\w.-]+)\s+(?<status>\d{3})/g;
const log = "example.com 200\nother.org 404\nthird.net 200";

for (const m of log.matchAll(re)) {
  const { host, status } = m.groups;
  console.log(`${host} returned ${status}`);
}

Named groups in replace

Named groups can be referenced in replacement strings using $<name>:

// Reformat YYYY-MM-DD to DD/MM/YYYY
"2024-03-15".replace(
  /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/,
  "$<day>/$<month>/$<year>"
);
// "15/03/2024"

In Python, use \g<name> in the replacement:

import re
re.sub(r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})",
       r"\g<day>/\g<month>/\g<year>",
       "2024-03-15")
# "15/03/2024"
JavaScript — editable, runs in your browser

Where to go next

Next: non-capturing groups(?:…) gives you grouping for quantifiers and alternation without the overhead of capturing.

Finished reading? Mark it complete to track your progress.

On this page