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

Non-Capturing Groups — (?:...)

~6 min · non-capturing, performance

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

Group without allocating a capture slot

(?:...) behaves like (...) for grouping purposes — quantifiers and alternation work the same — but does NOT capture the matched text into a numbered group. The match exists; it just doesn't get a slot.

Why bother

Three reasons to prefer non-capturing when you don't need the value:

  1. Clarity. The reader sees (?:...) and immediately knows "this is grouping, not extraction." Capturing groups raise the question "what's this for?"
  2. Group numbering stability. If you add or remove a non-capturing group, the numbers of capturing groups elsewhere don't shift. With pure (...), every change to the pattern can renumber every reference downstream.
  3. Slight performance. No capture slot to allocate. Tiny gain, but free.

The 'I'll capture everything just in case' anti-pattern

Beginners often capture every group reflexively, then never use most of the captures. The result: noisy code, brittle group numbers, slightly slower matching. Capture only what you'll actually use; non-capture everything else.

Code

Non-capturing groups in practice·python
import re

# Capturing — gives you 'http://example.com' in group 1
re.findall(r'((?:https?://)[\w.-]+)', 'visit http://a.com and https://b.com')
# ['http://a.com', 'https://b.com']

# Same pattern, all-capturing — extra capture slot for protocol
re.findall(r'((https?://)[\w.-]+)', 'visit http://a.com and https://b.com')
# [('http://a.com', 'http://'), ('https://b.com', 'https://')]
# Now you have a tuple per match, even though you only wanted the URL

# Non-capturing for alternation
re.findall(r'(?:cat|dog|fish)', 'cat fish dog cat')
# ['cat', 'fish', 'dog', 'cat']  — clean list

# Capturing alternation — adds noise
re.findall(r'(cat|dog|fish)', 'cat fish dog cat')
# ['cat', 'fish', 'dog', 'cat']  — looks the same, but group 1 is allocated

External links

Exercise

Find a regex in your code with multiple parens. Convert every group you don't actually use to (?:...). Re-run your tests. The behavior should be identical, the pattern should read more cleanly.

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.