Regex Capture Groups
How They Work and When to Use Them
Extract exactly the part you need, reference it in replacements, and keep your patterns readable with named groups.
Regex capture groups — written as (pattern) — do two things at once: they group tokens so you can apply quantifiers to a whole sub-expression, and they capture the matched text so you can extract or reuse it. Understanding groups is the difference between a regex that tells you "match found" and one that hands you the specific data you were after.
Basic Capture Groups
Wrap any part of your pattern in () and you get a numbered capture group. Group 1 is the first opening parenthesis, group 2 is the second, and so on.
// Pattern: extract year, month, day from a date string
const pattern = /(\d{4})-(\d{2})-(\d{2})/;
const match = '2026-05-01'.match(pattern);
match[0] // '2026-05-01' — full match
match[1] // '2026' — group 1 (year)
match[2] // '05' — group 2 (month)
match[3] // '01' — group 3 (day)
Non-Capturing Groups (?:)
If you need grouping for alternation or quantifiers but don't need to store the match, use (?:). It keeps your group numbering clean and runs slightly faster.
// Match 'colour' or 'color' — no need to capture the 'u'
/colou?r/ // simple, works fine here
/colo(?:u)?r/ // explicit non-capturing group
// Match http or https — the 's' is optional but not worth capturing
/https?:\/\// // simpler
/http(?:s)?:\/\// // non-capturing group version
// Alternation without polluting capture groups
/(?:jpg|jpeg|png|gif)$/i // matches image extensions
Named Capture Groups
Named groups let you reference matches by a meaningful name instead of a fragile position number. When you add a group or rearrange the pattern, named references still work.
// JavaScript — (?<name>pattern)
const pattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const { year, month, day } = '2026-05-01'.match(pattern).groups;
// year='2026', month='05', day='01'
// Python — (?P<name>pattern)
import re
pattern = re.compile(r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})')
m = pattern.match('2026-05-01')
m.group('year') # '2026'
Capture Groups in Replacements
Groups are most powerful in find-and-replace operations. Reference them in the replacement string to rearrange or reformat matched text.
// Reformat date from YYYY-MM-DD to DD/MM/YYYY
'2026-05-01'.replace(
/(\d{4})-(\d{2})-(\d{2})/,
'$3/$2/$1'
);
// Result: '01/05/2026'
// Wrap email addresses in mailto links
text.replace(
/([a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,})/g,
'<a href="mailto:$1">$1</a>'
);
// Python: use \1 or \g<name> in replacement
re.sub(r'(\d{4})-(\d{2})-(\d{2})', r'\3/\2/\1', '2026-05-01')
Backreferences — Match the Same Text Twice
A backreference (\1, \2) matches the exact same string that a previous group captured. This is useful for detecting repeated words, matching balanced quotes, or finding duplicate tokens.
// Match quoted strings where quotes must match
/(['"])(.+?)\1/
// Matches: 'hello' "world"
// No match: 'mismatched"
// Detect doubled words in text
/\b(\w+)\s+\1\b/gi
// Matches: 'the the' 'is is' 'very Very'
// Match repeated HTML tags
/<(\w+)>.*?<\/\1>/s
// Matches: <p>content</p> <div>...</div>
Practical Examples
/\[(?<level>INFO|WARN|ERROR)\]\s+(?<msg>.+)/
/(?<key>\w+)=(?<value>[^\s]+)/
/^(?<proto>https?):\/\/(?<host>[^\/]+)(?<path>\/.*)?$/
/(?:^|,)(?:"([^"]*(?:""[^"]*)*)"|([^,]*))/g
Common Mistakes
Test Your Capture Groups
The regex tester shows each capture group's match separately — paste any pattern from this page and see groups highlighted in real time.
Open Regex Tester →