JS RegExp Groups
In this page:
Basic Capturing Groups
Wrapping part of a pattern in parentheses, like (\d{3})-(\d{4}), captures each parenthesized section separately -- calling .match() on a matching string returns an array where index 0 is the full match, and each following index corresponds to one captured group, in order.
Note: Number capturing groups mentally in the order their opening parenthesis appears, left to right, to correctly index into the match result array.
Warning: Forgetting that match()[0] is the full match (not the first captured group) is a very common off-by-one mistake when reading results.
Example: Basic Capturing Groups
const match = "555-1234".match(/(\d{3})-(\d{4})/);
console.log(match[0], match[1], match[2]);
Non-Capturing Groups: (?:...)
A non-capturing group, written (?:pattern), groups part of a pattern (for applying a quantifier, or organizing alternation) without adding an entry to the array of captured results -- useful when you need grouping purely for structure, not for extracting that piece separately.
Note: Use (?:...) whenever a group exists purely for structural grouping (like applying a quantifier to an alternation) and its content does not need to be individually extracted.
Warning: Using a regular capturing group everywhere, even when the captured value is never actually used, needlessly clutters the match result array with unused entries.
Example: Non-Capturing Groups: (?:...)
const match = "abcabc".match(/(?:abc)+/);
console.log(match[0]); // grouped for the +, but not captured separately
Named Capturing Groups: (?<name>...)
Instead of referencing a captured group by its numeric position, (?<name>pattern) assigns it a readable name, accessible afterward via match.groups.name -- making code that works with several captured pieces significantly clearer than relying on numbered positions.
Note: Prefer named groups over numeric indices whenever a pattern captures several pieces, since match.groups.year reads far more clearly than match[1].
Warning: Renumbering or reordering groups in a pattern that relies on numeric indices requires updating every reference to those indices -- named groups avoid this fragility entirely.
Example: Named Capturing Groups: (?<name>...)
const match = "2024-06-15".match(/(?<year>\d{4})-(?<month>\d{2})/);
console.log(match.groups.year, match.groups.month);
Backreferences: Reusing a Captured Group
A backreference, written \1 (or \k<name> for a named group), refers back to whatever a previous group in the same pattern actually matched -- useful for finding repeated content, like a word that appears twice in a row, without hardcoding what that repeated content actually is.
Note: Use a backreference specifically when you need to match "the same thing again" without knowing in advance what that specific text will be.
Warning: A backreference matches the exact text the group captured during THIS specific match attempt -- it is not a fixed pattern, and different matches in the same string can have different backreferenced content.
Example: Backreferences: Reusing a Captured Group
console.log(/(\w+) \1/.test("hello hello")); // true, same word repeated
A Practical Example: Parsing a Full Name
Combining named capturing groups with a realistic pattern -- extracting a first and last name from a full name string, or breaking a URL into its component parts -- illustrates how groups turn a single matched pattern into several individually usable pieces of extracted data.
Note: Design capturing groups around the actual pieces of data you need to use separately afterward, not around how the pattern happens to naturally break into pieces visually.
Warning: A parsing pattern assuming a rigid, fixed structure (like always exactly "First Last") will fail on real-world input that does not follow that exact assumption, like a middle name or a single-word name.
Example: A Practical Example: Parsing a Full Name
const match = "Sam Sharma".match(/(?<first>\w+) (?<last>\w+)/);
console.log(match.groups.first, match.groups.last);
- Forgetting that match()'s result array places the full match at index 0, with captured groups starting at index 1, not 0.
- Using a capturing group when a non-capturing group (?:...) would be more appropriate, cluttering the match result with unwanted extra captured pieces.
- Mixing up backreference numbering when a pattern has several groups, referencing the wrong group number.
- (pattern) creates a capturing group, extracting that portion of the match separately.
- (?:pattern) creates a non-capturing group, useful for grouping without adding an entry to the captured results.
- (?<name>pattern) creates a named capturing group, accessible by name instead of numeric position for clearer code.
Capturing groups have been supported since JavaScript regex's earliest implementation; named capturing groups are supported in all current major browsers.
Chapter Quiz — Complete all 26 topics to unlock
0/26 topics done
Complete these topics first:
- JS JSON
- JS Regular Expressions
- JS Fetch API
- JS LocalStorage and SessionStorage
- JS Cookies
- JS setTimeout and setInterval
- JS Event Loop
- JS Web Workers
- JS Service Workers
- JS AJAX
- JS AJAX Intro
- JS AJAX XMLHttp
- JS AJAX Request
- JS AJAX Response
- JS AJAX XML
- JS AJAX PHP
- JS AJAX Database
- JS JSONP
- JS RegExp Flags
- JS RegExp Classes
- JS RegExp Metachars
- JS RegExp Assertions
- JS RegExp Groups
- JS RegExp Quantifiers
- JS JSON HTML
- JS JSON vs XML