Skip to content

Capturing Groups

Parentheses (…) serve two purposes: grouping (applying quantifiers or alternation to a subpattern) and capturing (saving the matched substring for later use).

Groups are numbered left-to-right by their opening parenthesis, starting at 1. Group 0 is always the entire match.


Basic Usage

// JS: extracting date parts
const m = "2024-03-15".match(/^(\d{4})-(\d{2})-(\d{2})$/);
// m[0] = "2024-03-15"  (full match)
// m[1] = "2024"        (group 1)
// m[2] = "03"          (group 2)
// m[3] = "15"          (group 3)
# Python
m = re.match(r'^(\d{4})-(\d{2})-(\d{2})$', '2024-03-15')
m.group(1)  # '2024'
m.group(2)  # '03'
m.groups()  # ('2024', '03', '15')

Nested Groups — Numbering

(a(b(c)))    # groups: 1=abc, 2=bc, 3=c
             # outer-to-inner, left-to-right opening paren

((a)(b))     # groups: 1=ab, 2=a, 3=b

The rule: count opening parentheses left to right to get the group number.


Repeated Groups

// A group inside a quantifier captures only the LAST iteration
const m = "aababc".match(/([a-c]+){3}/);
// m[1] = "c" — only the last repetition

To capture all iterations, use matchAll() or a loop with exec().


Group 0 — The Full Match

In every language, group/match index 0 is always the entire matched string:

"hello world".match(/(\w+)\s(\w+)/)[0]  // "hello world"
"hello world".match(/(\w+)\s(\w+)/)[1]  // "hello"
"hello world".match(/(\w+)\s(\w+)/)[2]  // "world"

When a Group Doesn't Participate

In alternation, some groups may not participate:

const m = "cat".match(/(cat)|(dog)/);
// m[1] = "cat"
// m[2] = undefined  — group 2 didn't participate

Check for undefined / None before using group values.