(?|…) — alternatives that share group numbers¶
One line: In a branch-reset group, every alternative numbers its capturing groups from the same starting point, so (?|(a)|(b)) has one group — group 1 — whichever branch matched; it exists in Perl and PCRE2 (so ABAP) and nowhere else on this page, and the ordinary (?:(a)|(b)) has two groups, one of which is always unset.
Level: reference · one construct, eight engines
What it means¶
Alternation and capturing fight each other: a date that is either 2026-09-22 or 22/09/2026 wants "the year" to be one group, but (\d{4})-(\d\d)-(\d\d)|(\d\d)/(\d\d)/(\d{4}) gives the year group 1 on one branch and group 6 on the other. (?|…) resets the counter at each |, so both branches put the year in group 1 — provided the branches are written in the same order.
Without it, the portable answers are a named group per branch with the same name (allowed in Perl, Ruby, Go and fancy-regex, refused by Python, Java and Rust — see named group), or two patterns and an if.
Measured¶
Verified output of kw_branch_reset_sh.sh — regenerated by tools/run_examples.py, never hand-typed.
construct python perl node ruby java go rust fancy
branch reset - bb - - - - - -
without it, \1 is unset no no b no no - - no
group number after it - cb - - - - - -
Reading the table¶
- Row 1.
(?|(a)|(b))\1onbb: Perl matchesbb. Thebbranch's group is group 1, and\1refers to it. Every other engine refuses the syntax. - Row 2.
(?:(a)|(b))\1— the same shape without the reset — answersnoin Python, Perl, Ruby, Java andfancy-regex: group 1 is on the branch not taken, so it is unset and\1cannot match. JavaScript answersb, because an unset group there matches the empty string — the backreference page's row 2 again. - Row 3. After the branch-reset group, numbering continues from the highest number any branch reached:
(?|(a)|(b))(c)onbcwith the replacement$2$1givescb—(c)is group 2.
The trap¶
Only the portability one, and it is loud: the syntax is refused everywhere but Perl and PCRE2. The subtler point is inside the feature — the branches must define their groups in the same order for the sharing to mean anything, and nothing checks that they do.
Where it is measured in depth¶
- Forward references — what an unset group means per engine, which is why row 2 splits.
See also¶
- Alternation · Capturing group · Named group.
- Conditional — the other way to make a pattern's shape depend on which branch matched.