Skip to content

(?<name>…), (?P<name>…), (?'name'…) — three ways to name a group, four to refer to it

One line: A named group is a capturing group you refer to by a word instead of a number, and it is the single most portable-looking, least-portable feature in the language: (?<w>…) is refused by Python 3.12, (?P<w>…) is refused by JavaScript, Ruby and Java, and the backreference to a name is \k<w> in five engines and (?P=w) in Python — with no spelling that all eight accept.

Level: reference · one construct, eight engines

What it means

Numbers change when a pattern is edited; names do not. That is the whole case for naming, and it is a strong one. The cost is the spelling war:

To define Accepted by
(?<w>…) Perl, PCRE2, JavaScript, Ruby, Java, Go, Rust, fancy-regex — not Python 3.12
(?P<w>…) Python, Perl, PCRE2, Go, Rust, fancy-regex — not JavaScript, Ruby, Java
(?'w'…) Perl, PCRE2, Ruby, fancy-regex
To match the same text again Accepted by
\k<w> Perl, PCRE2, JavaScript, Ruby, Java, fancy-regex
(?P=w) Python, Perl, PCRE2, fancy-regex
\g{w} Perl, PCRE2
\k'w', \k{w} Perl, PCRE2, (Ruby for \k'w')

Go and Rust's regex can define names and cannot refer to one in the pattern at all — no backreferences — but both use ${w} in a replacement.

Measured

Verified output of kw_named_group_sh.sh — regenerated by tools/run_examples.py, never hand-typed.

construct             python  perl  node  ruby  java  go  rust  fancy
(?<w>...)             -       a     a     a     a     a   a     a
(?P<w>...)            a       a     -     -     -     a   a     a
(?'w'...)             -       a     -     a     -     -   -     a
\k<w> backreference   -       aa    aa    aa    aa    -   -     aa
(?P=w) backreference  aa      aa    -     -     -     -   -     aa
\g{w} backreference   -       aa    no    no    -     -   -     -
same name twice       -       b     n/a   b     -     b   -     b

Reading the table

  • Row 1, (?<w>a). Seven engines; Python is -. Python's re accepts (?<= and (?<! for lookbehind and nothing else after (?<. (Python 3.12 is what the probe runs; the same is true of 3.14.)
  • Row 2, (?P<w>a). Python's own spelling, adopted by PCRE2 — so ABAP — and by Go and Rust, both of which accept both. JavaScript, Ruby and Java refuse it.
  • Row 3, (?'w'a). Perl, Ruby and fancy-regex only. Rarely worth writing.
  • Rows 4–6, referring back. \k<w> works in six engines; (?P=w) in Python, Perl and fancy-regex; \g{w} in Perl alone — and JavaScript and Ruby compile \g{w} and match nothing, reading it as the literal text g{w}. Go and Rust refuse all three, correctly: they have no backreferences of any kind.
  • Row 7, the same name twice. Perl, Ruby, Go and fancy-regex allow (?<w>a)|(?<w>b) — one name, two alternatives, whichever matched. Python, Java and Rust's regex refuse. JavaScript is n/a: duplicate names in different alternatives are a post-ES2018 addition that Node 20 and Node 24 answer differently, so the driver did not ask.

The trap

The (?P<…> / (?<…> split, in both directions. A Python pattern with (?P<year>\d{4}) is a syntax error in JavaScript, Ruby and Java; a JavaScript pattern with (?<year>\d{4}) is a syntax error in Python. Neither error message says "use the other spelling". PCRE2, Perl, Go and Rust accept both, which is why a pattern tested in pcre2grep or in Go can still fail in one of the two languages it was destined for.

Where it is measured in depth

See also