C.W.K.
Stream
Lesson 05 of 12 · published

Branch Reset Groups — (?|...)

~6 min · branch-reset, pcre, advanced

Level 0Pattern-Curious
0 XP0/90 lessons0/15 achievements
0/100 XP to next level100 XP to go0% complete

Flatten capture numbering across alternatives

Normally, alternation inside a group still gives each alternative its own group numbers if they have inner groups. (a(b)c|d(e)f) has groups 1 (full), 2 (b), and 3 (e). The 'b' and 'e' get separate numbers even though they're alternatives.

Branch reset groups (?|...) reset the numbering for each alternative. (?|a(b)c|d(e)f) — group 1 is 'b' OR 'e', whichever matched. Cleaner if you want "the inner part of whichever branch matched."

Use case

When you have N alternative patterns and want a single capture slot for the meaningful part of each. Without branch reset, you'd have N capture slots, only one populated, and you'd have to walk them to find the non-None one.

Engine support

PCRE and Perl. Python's third-party regex module. Not in built-in re, JavaScript, .NET, or Go.

The portable workaround

Without branch reset, just use named groups with the same name in different alternatives. PCRE allows this; Python's regex module too. Built-in re rejects duplicate names. So if you need this and you're stuck on built-in re, post-process: pick the first non-None group.

Code

Branch reset groups·text
# In PCRE / PHP
// preg_match('/(?|a(b)c|d(e)f)/', 'def', $m)
// $m[1] = 'e'  — flat capture, no matter which alternative matched

# Python third-party 'regex' module
import regex
m = regex.match(r'(?|a(b)c|d(e)f)', 'def')
m.group(1)  # 'e'

# Built-in Python 're' workaround — alternation with separate groups
import re
m = re.match(r'(?:a(b)c|d(e)f)', 'def')
# m.group(1) is None (b didn't match)
# m.group(2) is 'e'
# Pick the first non-None
result = next(g for g in m.groups() if g is not None)
print(result)  # 'e'

External links

Exercise

Take a pattern with multiple alternatives that each have an inner capture (e.g., extracting a value from one of several formats). Without branch reset, you walk the groups looking for non-None. With it, you have one slot. Decide which approach fits your codebase style.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.