Here’s a detailed explanation with multiple examples of accessing matched groups in JavaScript regular expressions:
1. Basic Concept of Capturing Groups
Capturing groups are parts of a regex pattern enclosed in parentheses ( )
. They allow you to extract specific portions of a matched string.
2. Methods to Access Groups
a. RegExp.exec()
Returns an array containing the entire match and captured groups. Works with global (g
) and sticky (y
) flags.
const text = "User: Alice, Age: 25";
const regex = /User: (\w+), Age: (\d+)/;
const result = regex.exec(text);
console.log(result[0]); // "User: Alice, Age: 25" (full match)
console.log(result[1]); // "Alice" (1st group)
console.log(result[2]); // "25" (2nd group)
b. String.match()
Without the global flag, returns groups. With g
, returns all matches without groups.
// Without global flag (returns groups)
const match = text.match(regex);
console.log(match[1]); // "Alice"
// With global flag (ignores groups)
const globalRegex = /(\w+): (\d+)/g;
const globalMatches = "a:1 b:2".match(globalRegex);
console.log(globalMatches); // ["a:1", "b:2"] (no groups!)
3. Accessing Groups by Index
Groups are ordered by their opening parentheses (left to right), starting at index 1
.
Example: Date Parsing
const dateStr = "2024-07-20";
const dateRegex = /(\d{4})-(\d{2})-(\d{2})/;
const dateResult = dateRegex.exec(dateStr);
console.log(dateResult[1]); // "2024" (year)
console.log(dateResult[2]); // "07" (month)
console.log(dateResult[3]); // "20" (day)
4. Named Capturing Groups (ES2018+)
Use (?<name>...)
syntax to name groups. Access via the groups
property.
const namedRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const namedResult = namedRegex.exec(dateStr);
console.log(namedResult.groups.year); // "2024"
console.log(namedResult.groups.month); // "07"
console.log(namedResult.groups.day); // "20"
Destructuring Named Groups:
const { groups: { year, month, day } } = namedRegex.exec(dateStr);
console.log(year); // "2024"
5. Global Flag (g
) and Groups
To get groups for multiple matches, use exec()
in a loop:
const log = "Error: 404, User: Bob; Error: 500, User: Eve";
const errorRegex = /Error: (\d+), User: (\w+)/g;
let match;
while ((match = errorRegex.exec(log)) !== null) {
console.log(`Code: ${match[1]}, User: ${match[2]}`);
}
// Output:
// Code: 404, User: Bob
// Code: 500, User: Eve
6. Optional and Nested Groups
a. Optional Groups
A group may return undefined
if not matched:
const optionalRegex = /(\d+)?-(.*)/;
const optionalMatch = optionalRegex.exec("-hello");
console.log(optionalMatch[1]); // undefined (no digits)
console.log(optionalMatch[2]); // "hello"
b. Nested Groups
Groups are ordered by their opening parentheses:
const nestedRegex = /((\d{4})-(\d{2}))-(\d{2})/;
const nestedMatch = nestedRegex.exec("2024-07-20");
console.log(nestedMatch[1]); // "2024-07" (outer group)
console.log(nestedMatch[2]); // "2024" (inner group)
console.log(nestedMatch[3]); // "07" (inner group)
console.log(nestedMatch[4]); // "20" (last group)
7. Using Groups in String.replace()
Reference groups in replacements with $n
or $<name>
:
// Reformat a date (YYYY-MM-DD → DD/MM/YYYY)
const reformatted = "2024-07-20".replace(
/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/,
"$<day>/$<month>/$<year>"
);
console.log(reformatted); // "20/07/2024"
// Using indexed groups:
const reformattedIndexed = "2024-07-20".replace(
/(\d{4})-(\d{2})-(\d{2})/,
"$3/$2/$1"
);
console.log(reformattedIndexed); // "20/07/2024"
8. Edge Cases & Best Practices
a. Check for null
Matches
Always verify the result before accessing groups:
const noMatch = regex.exec("Invalid string");
if (noMatch) {
console.log(noMatch[1]); // Never runs
} else {
console.log("No match found");
}
b. Browser Compatibility
Named groups require ES2018+ (modern browsers only). Use Babel for older environments.
c. Performance
Avoid using regex for complex parsing (e.g., HTML/XML). Use dedicated parsers instead.
9. Full Example: URL Parsing
const url = "https://www.example.com:8080/path?query=123";
const urlRegex = /^(?<protocol>https?):\/\/(?<host>[\w.-]+)(?::(?<port>\d+))?(?<path>\/\S*?)(?<query>\?\S*)?$/;
const urlResult = urlRegex.exec(url);
if (urlResult) {
const { protocol, host, port, path, query } = urlResult.groups;
console.log("Protocol:", protocol); // "https"
console.log("Host:", host); // "www.example.com"
console.log("Port:", port || 80); // 8080
console.log("Path:", path); // "/path"
console.log("Query:", query); // "?query=123"
}
Summary
- Use
exec()
for precise control (especially with global regex). - Use
match()
for simple non-global cases. - Access groups by index (
result[1]
) or name (result.groups.name
). - Handle optional/nested groups carefully.
- Always check for
null
matches to avoid runtime errors.
This comprehensive approach ensures you can efficiently extract and manipulate data from strings using regex groups in JavaScript.