Capturing Groups
Learn capturing groups in JavaScript regular expressions: numbered groups, named groups, non-capturing groups, and how to extract matched text.
A capturing group is a part of a regular expression wrapped in parentheses (...). It does two things: it groups a piece of the pattern so quantifiers and alternation apply to the whole chunk, and it remembers the text that matched so you can read it back later.
This is what turns a regular expression from a yes/no test into a data-extraction tool. Instead of only knowing that a date matched, you can pull out the year, month, and day as separate pieces. This page covers numbered groups, named groups, non-capturing groups, and how groups behave with match, matchAll, and replace.
Understanding Capturing Groups
When a match is found, the whole match is stored at index 0 of the result array, and each capturing group is stored at the next indexes (1, 2, 3, …) in the order the groups' opening parentheses appear, left to right.
Syntax and Basic Usage
Here's a simple example:
match[0] is always the entire matched string. match[1] and match[2] hold the text captured by the first and second sets of parentheses. The groups are numbered by their opening (, so even nested groups have a predictable order (see below).
Advanced Usage and Techniques
Nested Capturing Groups
Groups can be nested, allowing more complex pattern matching. The numbering follows each opening parenthesis from left to right:
The outer group (group 1) captures foobar, while the inner groups (2 and 3) capture foo and bar separately. If a group is optional and doesn't participate in the match, its slot is undefined.
Non-Capturing Groups
Sometimes you want to group parts of a pattern — to apply a quantifier or alternation — without spending a numbered slot on it. Non-capturing groups use (?:...):
Here foo is grouped but not captured, so bar becomes group 1 instead of group 2. Non-capturing groups keep your result array clean and are slightly faster when you don't need the matched text.
A common use is repeating a chunk without capturing every repetition:
Practical Examples
Parsing Dates
Capturing groups can parse and reformat dates from strings:
This code extracts the year, month, and day, then formats the date in a different style.
Extracting Information from URLs
Another common use case is extracting parts of a URL:
This regular expression captures the protocol, domain, path, and query string separately.
Tips for Using Capturing Groups Effectively
- Plan Your Groups: Think ahead about what parts of the pattern you need to capture.
- Use Non-Capturing Groups When Needed: Use
(?:...)for grouping without capturing to simplify your match array. - Named Capturing Groups: In modern JavaScript (ES2018+), you can use named capturing groups for better readability.
- Global Flag Behavior: When using the
gflag withString.prototype.match(), it returns an array of all matched strings instead of capturing groups. UseString.prototype.matchAll()for detailed group extraction with the global flag.
Named Capturing Groups
Numbered groups are fragile: add a group in the middle and every index after it shifts. Named capturing groups (ES2018+) avoid this by labeling each group with (?<name>...). The captures appear on a groups object instead of (or in addition to) numbered indexes:
Prefer named capturing groups for anything beyond a trivial pattern — they make both the regex and the code that reads it self-documenting.
Using Groups with match, matchAll, and replace
How you read out captured groups depends on the method you call.
Without the g flag — match returns groups
A non-global String.prototype.match() returns a single match array with all groups, exactly like the examples above. This is the most common way to extract a single record.
With the g flag — use matchAll for groups
When you add the global flag g, match() returns a flat array of full-match strings only — the groups are lost. To get groups for every match, use String.prototype.matchAll(), which returns an iterator of match arrays (each with its own groups object):
Referring to groups in replace
In a String.prototype.replace() replacement string you can reference captures by number with $1, $2, … or by name with $<name>:
For more control, pass a function to replace. Its arguments are the full match, then each captured group, and (if you used names) a final groups object:
Backreferences
Once a group has captured text, you can match that same text again later in the same pattern using a backreference — \\1 for numbered groups or \\k<name> for named ones. This is handy for finding repeated words or matching paired quotes:
Backreferences are a topic of their own — see Backreferences in pattern for the full details.
Related Topics
- Alternation (OR)
|— groups are essential for scoping alternation. - Quantifiers
+ * ? {n}— apply repetition to a whole group. - Greedy and lazy quantifiers — control how much a group consumes.
- Backreferences
\1and\k<name>— reuse captured text within a pattern. - Patterns and flags — the
g,i, and other flags that affect matching.
Conclusion
Capturing groups in JavaScript regular expressions offer a robust way to work with complex string patterns. By mastering their use, you can perform sophisticated text manipulations, extract meaningful data, and handle replacements with ease. Whether you are parsing dates, processing URLs, or reformatting strings, capturing groups provide the flexibility and power needed for advanced text processing tasks. Explore these examples, practice with your own patterns, and enhance your JavaScript skills to handle any string manipulation challenge.