Note: Use literals /pattern/flags for static patterns (better performance);
constructor for dynamic patterns. Remember to double-escape backslashes in strings: '\\d' not
'\d'.
2. RegExp Flags and Global Modifiers
Flag
Name
Description
Effect
g
Global
Find all matches, not just first; affects exec(), test(), match(), replace()
Multiple matches
i
Ignore Case
Case-insensitive matching; [a-z] matches both cases
/a/i matches 'A' and 'a'
m
Multiline
^ and $ match line boundaries, not just string start/end
Full Unicode support; astral characters, Unicode escapes, properties
\u{1F600} and \p{...}
y ES2015
Sticky
Match must start at lastIndex; no skipping ahead
For tokenizers/parsers
d ES2022
Indices
Capture group indices in .indices property of match result
match.indices[0]
Example: Flag behaviors
const str = 'Hello World\nHello Again';// g - global (all matches)str.match(/hello/i); // ["Hello"] (first only)str.match(/hello/gi); // ["Hello", "Hello"] (all)/\d+/g.test('123'); // true/\d+/g.test('123'); // false (lastIndex moved!)// i - ignore case/hello/.test('HELLO'); // false/hello/i.test('HELLO'); // true// m - multiline (^ $ match line boundaries)const multi = 'line1\nline2\nline3';multi.match(/^line/g); // ["line"] (only first)multi.match(/^line/gm); // ["line", "line", "line"] (each line)/world$/.test('hello\nworld'); // true (end of string)/world$/m.test('world\nhello'); // true (end of line)// s - dotAll (. matches newlines)/.+/.test('hello\nworld'); // false (. stops at \n)/.+/s.test('hello\nworld'); // true (. matches \n)'a\nb'.match(/a.b/); // null'a\nb'.match(/a.b/s); // ["a\nb"]// u - unicode (proper astral character handling)'😀'.match(/./); // ["�"] ❌ (high surrogate only)'😀'.match(/./u); // ["😀"] ✓// Unicode property escapes (requires u flag)/\p{Emoji}/u.test('😀'); // true/\p{Script=Greek}/u.test('α'); // true/\p{Letter}/u.test('A'); // true// Count code points, not code units'😀'.length; // 2'😀'.match(/./gu); // ["😀"] (1 match)'😀'.match(/./g); // ["�","�"] (2 matches)// y - sticky (match at exact position)const sticky = /\d+/y;sticky.lastIndex = 0;sticky.exec('123 456'); // ["123"]sticky.lastIndex; // 3sticky.exec('123 456'); // null (position 3 is space)sticky.lastIndex; // 0 (reset on failure)// Without y, would skip ahead and match 456const notSticky = /\d+/g;notSticky.lastIndex = 3;notSticky.exec('123 456'); // ["456"]// d - indices (capture group positions)const indicesRe = /(\d+)-(\d+)/d;const match = indicesRe.exec('id: 123-456');match[1]; // "123"match[2]; // "456"match.indices[1]; // [4, 7] (position of "123")match.indices[2]; // [8, 11] (position of "456")// Combine flagsconst combined = /pattern/gimsu;combined.flags; // "gimsu" (alphabetically sorted)
Warning: Global g flag makes RegExp stateful
(lastIndex). Reset with regex.lastIndex = 0 or use string methods. Always use u flag
for Unicode text!
3. Pattern Matching Methods (test, exec, match)
Method
Syntax
Description
Returns
test()
regex.test(str)
Check if pattern matches; fastest for existence check
Boolean
exec()
regex.exec(str)
Get match details with capture groups; use in loop with /g flag
Array | null
match()
str.match(regex)
Without /g: like exec(); with /g: array of all matches (no details)
Array | null
matchAll() ES2020
str.matchAll(regex)
Iterator of all matches with full details; regex must have /g
Iterator
Example: Pattern matching methods
const str = 'The year 2025 and 2026';// test() - simple existence check/\d+/.test(str); // true/cat/.test(str); // false// Use for validationfunction isEmail(email) { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);}// exec() - detailed match infoconst yearRe = /(\d{4})/;const match = yearRe.exec(str);match[0]; // "2025" (full match)match[1]; // "2025" (capture group 1)match.index; // 9 (position)match.input; // original string// exec() with /g flag (iterate)const yearReGlobal = /(\d{4})/g;let m;while ((m = yearReGlobal.exec(str)) !== null) { console.log(m[1], 'at', m.index); // "2025" at 9 // "2026" at 18}// match() without /g (same as exec)str.match(/(\d{4})/);// ["2025", "2025", index: 9, input: "...", groups: undefined]// match() with /g (all matches, no details)str.match(/\d{4}/g); // ["2025", "2026"]str.match(/\d+/g); // ["2025", "2026"]// matchAll() - best of both (ES2020+)const years = str.matchAll(/(\d{4})/g);for (const match of years) { console.log(match[1], 'at', match.index); // "2025" at 9 // "2026" at 18}// Convert to arrayconst allMatches = [...str.matchAll(/(\d{4})/g)];// Named capture groupsconst phoneRe = /(?<area>\d{3})-(?<exchange>\d{3})-(?<number>\d{4})/;const phone = '555-123-4567';const phoneMatch = phone.match(phoneRe);phoneMatch[1]; // "555"phoneMatch.groups.area; // "555"phoneMatch.groups.exchange; // "123"phoneMatch.groups.number; // "4567"// Multiple patternsconst email = 'user@example.com';const emailRe = /^(?<user>[^@]+)@(?<domain>[^@]+)$/;const emailMatch = email.match(emailRe);emailMatch.groups.user; // "user"emailMatch.groups.domain; // "example.com"// No match returns null'abc'.match(/\d+/); // null/\d+/.test('abc'); // false/\d+/.exec('abc'); // null// Global test() gotcha (stateful!)const re = /test/g;re.test('test test'); // true (first call)re.test('test test'); // true (second call)re.test('test test'); // false! (lastIndex past end)re.lastIndex; // 0 (reset)// Solution: don't reuse global regex for test()function hasDigit(str) { return /\d/.test(str); // no /g, always works}// Or reset lastIndexfunction hasPattern(str, regex) { regex.lastIndex = 0; return regex.test(str);}
Note: Use test() for boolean checks; match() for simple extraction;
matchAll() for all matches with details. Avoid test() with global regex in loops
(stateful).
4. String RegExp Methods (replace, split, search)
Method
Syntax
Description
Returns
replace()
str.replace(regex, newStr|fn)
Replace first match (or all with /g); newStr can use $1, $2, etc.
String
replaceAll() ES2021
str.replaceAll(str|regex, newStr|fn)
Replace all occurrences; regex must have /g flag
String
split()
str.split(regex, limit)
Split string by pattern; optional limit; capture groups included in result
Array
search()
str.search(regex)
Find index of first match; ignores /g flag; like indexOf for regex
Note: Use literals /pattern/flags for static patterns (better performance);
constructor for dynamic patterns. Remember to double-escape backslashes in strings: '\\d' not
'\d'.
2. RegExp Flags and Global Modifiers
Flag
Name
Description
Effect
g
Global
Find all matches, not just first; affects exec(), test(), match(), replace()
Multiple matches
i
Ignore Case
Case-insensitive matching; [a-z] matches both cases
/a/i matches 'A' and 'a'
m
Multiline
^ and $ match line boundaries, not just string start/end
Full Unicode support; astral characters, Unicode escapes, properties
\u{1F600} and \p{...}
y ES2015
Sticky
Match must start at lastIndex; no skipping ahead
For tokenizers/parsers
d ES2022
Indices
Capture group indices in .indices property of match result
match.indices[0]
Example: Flag behaviors
const str = 'Hello World\nHello Again';// g - global (all matches)str.match(/hello/i); // ["Hello"] (first only)str.match(/hello/gi); // ["Hello", "Hello"] (all)/\d+/g.test('123'); // true/\d+/g.test('123'); // false (lastIndex moved!)// i - ignore case/hello/.test('HELLO'); // false/hello/i.test('HELLO'); // true// m - multiline (^ $ match line boundaries)const multi = 'line1\nline2\nline3';multi.match(/^line/g); // ["line"] (only first)multi.match(/^line/gm); // ["line", "line", "line"] (each line)/world$/.test('hello\nworld'); // true (end of string)/world$/m.test('world\nhello'); // true (end of line)// s - dotAll (. matches newlines)/.+/.test('hello\nworld'); // false (. stops at \n)/.+/s.test('hello\nworld'); // true (. matches \n)'a\nb'.match(/a.b/); // null'a\nb'.match(/a.b/s); // ["a\nb"]// u - unicode (proper astral character handling)'😀'.match(/./); // ["�"] ❌ (high surrogate only)'😀'.match(/./u); // ["😀"] ✓// Unicode property escapes (requires u flag)/\p{Emoji}/u.test('😀'); // true/\p{Script=Greek}/u.test('α'); // true/\p{Letter}/u.test('A'); // true// Count code points, not code units'😀'.length; // 2'😀'.match(/./gu); // ["😀"] (1 match)'😀'.match(/./g); // ["�","�"] (2 matches)// y - sticky (match at exact position)const sticky = /\d+/y;sticky.lastIndex = 0;sticky.exec('123 456'); // ["123"]sticky.lastIndex; // 3sticky.exec('123 456'); // null (position 3 is space)sticky.lastIndex; // 0 (reset on failure)// Without y, would skip ahead and match 456const notSticky = /\d+/g;notSticky.lastIndex = 3;notSticky.exec('123 456'); // ["456"]// d - indices (capture group positions)const indicesRe = /(\d+)-(\d+)/d;const match = indicesRe.exec('id: 123-456');match[1]; // "123"match[2]; // "456"match.indices[1]; // [4, 7] (position of "123")match.indices[2]; // [8, 11] (position of "456")// Combine flagsconst combined = /pattern/gimsu;combined.flags; // "gimsu" (alphabetically sorted)
Warning: Global g flag makes RegExp stateful
(lastIndex). Reset with regex.lastIndex = 0 or use string methods. Always use u flag
for Unicode text!
3. Pattern Matching Methods (test, exec, match)
Method
Syntax
Description
Returns
test()
regex.test(str)
Check if pattern matches; fastest for existence check
Boolean
exec()
regex.exec(str)
Get match details with capture groups; use in loop with /g flag
Array | null
match()
str.match(regex)
Without /g: like exec(); with /g: array of all matches (no details)
Array | null
matchAll() ES2020
str.matchAll(regex)
Iterator of all matches with full details; regex must have /g
Iterator
Example: Pattern matching methods
const str = 'The year 2025 and 2026';// test() - simple existence check/\d+/.test(str); // true/cat/.test(str); // false// Use for validationfunction isEmail(email) { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);}// exec() - detailed match infoconst yearRe = /(\d{4})/;const match = yearRe.exec(str);match[0]; // "2025" (full match)match[1]; // "2025" (capture group 1)match.index; // 9 (position)match.input; // original string// exec() with /g flag (iterate)const yearReGlobal = /(\d{4})/g;let m;while ((m = yearReGlobal.exec(str)) !== null) { console.log(m[1], 'at', m.index); // "2025" at 9 // "2026" at 18}// match() without /g (same as exec)str.match(/(\d{4})/);// ["2025", "2025", index: 9, input: "...", groups: undefined]// match() with /g (all matches, no details)str.match(/\d{4}/g); // ["2025", "2026"]str.match(/\d+/g); // ["2025", "2026"]// matchAll() - best of both (ES2020+)const years = str.matchAll(/(\d{4})/g);for (const match of years) { console.log(match[1], 'at', match.index); // "2025" at 9 // "2026" at 18}// Convert to arrayconst allMatches = [...str.matchAll(/(\d{4})/g)];// Named capture groupsconst phoneRe = /(?<area>\d{3})-(?<exchange>\d{3})-(?<number>\d{4})/;const phone = '555-123-4567';const phoneMatch = phone.match(phoneRe);phoneMatch[1]; // "555"phoneMatch.groups.area; // "555"phoneMatch.groups.exchange; // "123"phoneMatch.groups.number; // "4567"// Multiple patternsconst email = 'user@example.com';const emailRe = /^(?<user>[^@]+)@(?<domain>[^@]+)$/;const emailMatch = email.match(emailRe);emailMatch.groups.user; // "user"emailMatch.groups.domain; // "example.com"// No match returns null'abc'.match(/\d+/); // null/\d+/.test('abc'); // false/\d+/.exec('abc'); // null// Global test() gotcha (stateful!)const re = /test/g;re.test('test test'); // true (first call)re.test('test test'); // true (second call)re.test('test test'); // false! (lastIndex past end)re.lastIndex; // 0 (reset)// Solution: don't reuse global regex for test()function hasDigit(str) { return /\d/.test(str); // no /g, always works}// Or reset lastIndexfunction hasPattern(str, regex) { regex.lastIndex = 0; return regex.test(str);}
Note: Use test() for boolean checks; match() for simple extraction;
matchAll() for all matches with details. Avoid test() with global regex in loops
(stateful).
4. String RegExp Methods (replace, split, search)
Method
Syntax
Description
Returns
replace()
str.replace(regex, newStr|fn)
Replace first match (or all with /g); newStr can use $1, $2, etc.
String
replaceAll() ES2021
str.replaceAll(str|regex, newStr|fn)
Replace all occurrences; regex must have /g flag
String
split()
str.split(regex, limit)
Split string by pattern; optional limit; capture groups included in result
Array
search()
str.search(regex)
Find index of first match; ignores /g flag; like indexOf for regex
Note: Use replace() with functions for complex transformations.
replaceAll() requires /g flag for regex. split() with capture groups includes
delimiters in result.
5. Character Classes and Quantifiers
Pattern
Matches
Description
Example
.
Any character
Except newline (unless /s flag); use [\s\S] or /s for any
/a.c/.test('abc') // true
\d
Digit [0-9]
ASCII digits only; use \p{N} with /u for Unicode digits
Warning: Greedy quantifiers (+, *) can cause catastrophic
backtracking with complex patterns. Use lazy quantifiers (+?, *?) or atomic groups
when appropriate.
// Positive lookahead (?=...)// Match digit followed by "px" but don't include "px"'5px 10em'.match(/\d+(?=px)/g); // ["5"]// Password validation (at least one digit)/^(?=.*\d).{8,}$/.test('Pass123!'); // true/^(?=.*\d).{8,}$/.test('Password'); // false (no digit)// Multiple lookaheads (AND conditions)const strongPassword = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&]).{8,}$/;strongPassword.test('Pass123!'); // truestrongPassword.test('password'); // false (no uppercase, digit, special)// Negative lookahead (?!...)// Match word NOT followed by "script"'Java JavaScript'.match(/\bJava(?!Script)\b/); // ["Java"]// Select numbers not followed by px'5px 10em 15%'.match(/\d+(?!px)/g); // ["1", "0", "1", "5"]// (matches last digit of 10, and 15)// Better: not followed by px unit'5px 10em 15%'.match(/\d+(?!px\b)/g); // ["10", "15"]// Positive lookbehind (?<=...)// Match digits preceded by $'$50 €30 £40'.match(/(?<=\$)\d+/g); // ["50"]// Extract value after key'price=100 quantity=5'.match(/(?<==)\d+/g);// ["100", "5"]// Match word after "Mr. "'Mr. Smith, Ms. Jones'.match(/(?<=Mr\. )\w+/);// ["Smith"]// Negative lookbehind (?<!...)// Match digits NOT preceded by $'$50 €30 £40'.match(/(?<!\$)\d+/g); // ["30", "40"]// Word not preceded by "no "'no cats, dogs, no birds'.match(/(?<!no )\b\w+s\b/g);// ["dogs"] (cats and birds are preceded by "no ")// Complex combinations// 1. Price in $ (with decimal)const priceRe = /(?<=\$)\d+(?:\.\d{2})?(?=\s|$)/g;'Items: $10.50 and $25.00'.match(priceRe);// ["10.50", "25.00"]// 2. Password: 8+ chars, has lowercase, uppercase, digitconst passRe = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/;passRe.test('Secure123'); // truepassRe.test('secure123'); // false (no uppercase)passRe.test('SECURE123'); // false (no lowercase)passRe.test('SecurePass'); // false (no digit)// 3. Extract hashtags not in code blocks// (not preceded by backtick)const text = 'Use #javascript but not `#code`';text.match(/(?<!`[^`]*)#\w+(?![^`]*`)/g); // ["#javascript"]// 4. Numbers with thousands separatorconst numRe = /\b(?<!\d,)\d{1,3}(?:,\d{3})*(?!\d)/g;'1,000 and 10,000 and 999'.match(numRe);// ["1,000", "10,000", "999"]// 5. Email username (before @)const emailRe = /\w+(?=@)/;'user@example.com'.match(emailRe)[0]; // "user"// 6. URL domain (after //)const domainRe = /(?<=:\/\/)[^\/]+/;'https://example.com/path'.match(domainRe)[0];// "example.com"// 7. Word boundaries with punctuation// Word not followed by alphanumeric'hello, world!'.match(/\w+(?!\w)/g);// ["hello", "world"]// 8. CSS selector (class not in comments)const css = '.btn { } /* .comment */';css.match(/(?<!\/\*.*)\.[a-z-]+(?!.*\*\/)/g);// Tricky - better parsed differently// Zero-width assertion chaining// Number between 1-100/^(?=\d{1,3}$)(?!0$)([1-9]\d?|100)$/.test('50'); // true/^(?=\d{1,3}$)(?!0$)([1-9]\d?|100)$/.test('0'); // false/^(?=\d{1,3}$)(?!0$)([1-9]\d?|100)$/.test('101'); // false// Assertions don't consume charactersconst re = /(?=\d{3})\d{2}/;re.exec('12345'); // ["12"] (matched at position 0)// Lookahead checked 3 digits, but only consumed 2// Use in replace// Insert comma in numbers'1234567'.replace(/\B(?=(\d{3})+(?!\d))/g, ',');// "1,234,567"
Note: Assertions are zero-width (don't consume characters).
Lookaheads work everywhere; lookbehinds require ES2018+. Use for complex validations and extractions.
7. Named Capture Groups and Replacement
Feature
Syntax
Description
Example
Named Group
(?<name>pattern)
Capture group with identifier; access via .groups property
/(?<year>\d{4})/
Group Reference
\k<name>
Backreference to named group within pattern
/(?<tag>\w+)</\k<tag>/
Replacement
$<name>
Reference named group in replacement string
.replace(re, '$<name>')
Non-capturing Group
(?:pattern)
Group without capturing; for grouping only; better performance
/(?:abc)+/
Numbered Group
(pattern)
Traditional capture group; access via index
/(\d+)/
Backreference
\1 \2 ...
Reference numbered group within pattern
/(\w)\1/ (double char)
Example: Named groups and backreferences
// Named capture groupsconst dateRe = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;const match = '2025-12-17'.match(dateRe);match[1]; // "2025" (by index)match.groups.year; // "2025" (by name)match.groups.month; // "12"match.groups.day; // "17"// Destructuring with named groupsconst {groups: {year, month, day}} = '2025-12-17'.match(dateRe);console.log(year, month, day); // "2025" "12" "17"// Replace with named groupsconst date = '2025-12-17';date.replace(dateRe, '
// Named capture groups
const dateRe = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2025-12-17'.match(dateRe);
match[1]; // "2025" (by index)
match.groups.year; // "2025" (by name)
match.groups.month; // "12"
match.groups.day; // "17"
// Destructuring with named groups
const {groups: {year, month, day}} = '2025-12-17'.match(dateRe);
console.log(year, month, day); // "2025" "12" "17"
// Replace with named groups
const date = '2025-12-17';
date.replace(dateRe, '$<month>/$<day>/$<year>');
// "12/17/2025"
// Function replacement with named groups
date.replace(dateRe, (match, y, m, d, offset, str, groups) => {
return `${groups.month}/${groups.day}/${groups.year}`;
});
// Backreference to named group
const htmlTag = /<(?<tag>\w+)>.*?<\/\k<tag>>/;
htmlTag.test('<div>content</div>'); // true
htmlTag.test('<div>content</span>'); // false (tag mismatch)
// Find duplicate words
const duplicateRe = /\b(?<word>\w+)\s+\k<word>\b/i;
duplicateRe.test('the the'); // true
duplicateRe.test('the cat'); // false
// Email parsing
const emailRe = /^(?<user>[^\s@]+)@(?<domain>[^\s@]+)\.(?<tld>\w+)$/;
const email = 'user@example.com'.match(emailRe);
email.groups.user; // "user"
email.groups.domain; // "example"
email.groups.tld; // "com"
// URL parsing
const urlRe = /^(?<protocol>https?):\/\/(?<domain>[^\/]+)(?<path>\/.*)?$/;
const url = 'https://example.com/path/to/page'.match(urlRe);
url.groups.protocol; // "https"
url.groups.domain; // "example.com"
url.groups.path; // "/path/to/page"
// Phone number formatting
const phoneRe = /(?<area>\d{3})(?<exchange>\d{3})(?<number>\d{4})/;
'5551234567'.replace(phoneRe, '($<area>) $<exchange>-$<number>');
// "(555) 123-4567"
// Non-capturing groups (?:...)
// Group without capturing (performance)
/(?:abc)+/.test('abcabc'); // true
'abcabc'.match(/(?:abc)+/)[0]; // "abcabc"
'abcabc'.match(/(?:abc)+/).length; // 1 (no capture groups)
// Compare to capturing
'abcabc'.match(/(abc)+/); // ["abcabc", "abc"] (has capture)
// Use for alternation
/(?:cat|dog)s?/.test('cats'); // true (s is optional for whole group)
// Numbered backreferences
// Find doubled characters
/(\w)\1/.test('hello'); // true (ll)
'hello'.match(/(\w)\1/)[0]; // "ll"
// Find repeated words
/(\b\w+\b)\s+\1/.test('the the'); // true
// Match balanced quotes
/'([^']*)'/.exec("'hello'")[1]; // "hello"
// HTML attributes
/(\w+)="([^"]*)"/.exec('class="btn"');
// ["class=\"btn\"", "class", "btn"]
// Combining named and numbered groups
const re = /(?<name>\w+):(\d+)/;
const m = 'user:123'.match(re);
m.groups.name; // "user"
m[2]; // "123" (numbered after named)
// Replace with function (named groups)
'John Smith, Jane Doe'.replace(
/(?<first>\w+) (?<last>\w+)/g,
(match, first, last, offset, string, groups) => {
return `${groups.last}, ${groups.first}`;
}
);
// "Smith, John, Doe, Jane"
// Case conversion in replacement
'user_name'.replace(
/_(?<char>\w)/g,
(match, char, offset, string, groups) => {
return groups.char.toUpperCase();
}
);
// "userName"
// Swap parts
'firstName lastName'.replace(
/(?<first>\w+) (?<last>\w+)/,
'$<last> $<first>'
);
// "lastName firstName"
// Optional named groups
const optionalRe = /(?<protocol>https?:\/\/)?(?<domain>[^\/]+)/;
'example.com'.match(optionalRe).groups;
// {protocol: undefined, domain: "example.com"}
'https://example.com'.match(optionalRe).groups;
// {protocol: "https://", domain: "example.com"}
// matchAll with named groups
const text = 'user:123 admin:456';
const matches = text.matchAll(/(?<role>\w+):(?<id>\d+)/g);
for (const match of matches) {
console.log(match.groups.role, match.groups.id);
// "user" "123"
// "admin" "456"
}
#x3C;month>/
// Named capture groups
const dateRe = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2025-12-17'.match(dateRe);
match[1]; // "2025" (by index)
match.groups.year; // "2025" (by name)
match.groups.month; // "12"
match.groups.day; // "17"
// Destructuring with named groups
const {groups: {year, month, day}} = '2025-12-17'.match(dateRe);
console.log(year, month, day); // "2025" "12" "17"
// Replace with named groups
const date = '2025-12-17';
date.replace(dateRe, '$<month>/$<day>/$<year>');
// "12/17/2025"
// Function replacement with named groups
date.replace(dateRe, (match, y, m, d, offset, str, groups) => {
return `${groups.month}/${groups.day}/${groups.year}`;
});
// Backreference to named group
const htmlTag = /<(?<tag>\w+)>.*?<\/\k<tag>>/;
htmlTag.test('<div>content</div>'); // true
htmlTag.test('<div>content</span>'); // false (tag mismatch)
// Find duplicate words
const duplicateRe = /\b(?<word>\w+)\s+\k<word>\b/i;
duplicateRe.test('the the'); // true
duplicateRe.test('the cat'); // false
// Email parsing
const emailRe = /^(?<user>[^\s@]+)@(?<domain>[^\s@]+)\.(?<tld>\w+)$/;
const email = 'user@example.com'.match(emailRe);
email.groups.user; // "user"
email.groups.domain; // "example"
email.groups.tld; // "com"
// URL parsing
const urlRe = /^(?<protocol>https?):\/\/(?<domain>[^\/]+)(?<path>\/.*)?$/;
const url = 'https://example.com/path/to/page'.match(urlRe);
url.groups.protocol; // "https"
url.groups.domain; // "example.com"
url.groups.path; // "/path/to/page"
// Phone number formatting
const phoneRe = /(?<area>\d{3})(?<exchange>\d{3})(?<number>\d{4})/;
'5551234567'.replace(phoneRe, '($<area>) $<exchange>-$<number>');
// "(555) 123-4567"
// Non-capturing groups (?:...)
// Group without capturing (performance)
/(?:abc)+/.test('abcabc'); // true
'abcabc'.match(/(?:abc)+/)[0]; // "abcabc"
'abcabc'.match(/(?:abc)+/).length; // 1 (no capture groups)
// Compare to capturing
'abcabc'.match(/(abc)+/); // ["abcabc", "abc"] (has capture)
// Use for alternation
/(?:cat|dog)s?/.test('cats'); // true (s is optional for whole group)
// Numbered backreferences
// Find doubled characters
/(\w)\1/.test('hello'); // true (ll)
'hello'.match(/(\w)\1/)[0]; // "ll"
// Find repeated words
/(\b\w+\b)\s+\1/.test('the the'); // true
// Match balanced quotes
/'([^']*)'/.exec("'hello'")[1]; // "hello"
// HTML attributes
/(\w+)="([^"]*)"/.exec('class="btn"');
// ["class=\"btn\"", "class", "btn"]
// Combining named and numbered groups
const re = /(?<name>\w+):(\d+)/;
const m = 'user:123'.match(re);
m.groups.name; // "user"
m[2]; // "123" (numbered after named)
// Replace with function (named groups)
'John Smith, Jane Doe'.replace(
/(?<first>\w+) (?<last>\w+)/g,
(match, first, last, offset, string, groups) => {
return `${groups.last}, ${groups.first}`;
}
);
// "Smith, John, Doe, Jane"
// Case conversion in replacement
'user_name'.replace(
/_(?<char>\w)/g,
(match, char, offset, string, groups) => {
return groups.char.toUpperCase();
}
);
// "userName"
// Swap parts
'firstName lastName'.replace(
/(?<first>\w+) (?<last>\w+)/,
'$<last> $<first>'
);
// "lastName firstName"
// Optional named groups
const optionalRe = /(?<protocol>https?:\/\/)?(?<domain>[^\/]+)/;
'example.com'.match(optionalRe).groups;
// {protocol: undefined, domain: "example.com"}
'https://example.com'.match(optionalRe).groups;
// {protocol: "https://", domain: "example.com"}
// matchAll with named groups
const text = 'user:123 admin:456';
const matches = text.matchAll(/(?<role>\w+):(?<id>\d+)/g);
for (const match of matches) {
console.log(match.groups.role, match.groups.id);
// "user" "123"
// "admin" "456"
}
#x3C;day>/
// Named capture groups
const dateRe = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2025-12-17'.match(dateRe);
match[1]; // "2025" (by index)
match.groups.year; // "2025" (by name)
match.groups.month; // "12"
match.groups.day; // "17"
// Destructuring with named groups
const {groups: {year, month, day}} = '2025-12-17'.match(dateRe);
console.log(year, month, day); // "2025" "12" "17"
// Replace with named groups
const date = '2025-12-17';
date.replace(dateRe, '$<month>/$<day>/$<year>');
// "12/17/2025"
// Function replacement with named groups
date.replace(dateRe, (match, y, m, d, offset, str, groups) => {
return `${groups.month}/${groups.day}/${groups.year}`;
});
// Backreference to named group
const htmlTag = /<(?<tag>\w+)>.*?<\/\k<tag>>/;
htmlTag.test('<div>content</div>'); // true
htmlTag.test('<div>content</span>'); // false (tag mismatch)
// Find duplicate words
const duplicateRe = /\b(?<word>\w+)\s+\k<word>\b/i;
duplicateRe.test('the the'); // true
duplicateRe.test('the cat'); // false
// Email parsing
const emailRe = /^(?<user>[^\s@]+)@(?<domain>[^\s@]+)\.(?<tld>\w+)$/;
const email = 'user@example.com'.match(emailRe);
email.groups.user; // "user"
email.groups.domain; // "example"
email.groups.tld; // "com"
// URL parsing
const urlRe = /^(?<protocol>https?):\/\/(?<domain>[^\/]+)(?<path>\/.*)?$/;
const url = 'https://example.com/path/to/page'.match(urlRe);
url.groups.protocol; // "https"
url.groups.domain; // "example.com"
url.groups.path; // "/path/to/page"
// Phone number formatting
const phoneRe = /(?<area>\d{3})(?<exchange>\d{3})(?<number>\d{4})/;
'5551234567'.replace(phoneRe, '($<area>) $<exchange>-$<number>');
// "(555) 123-4567"
// Non-capturing groups (?:...)
// Group without capturing (performance)
/(?:abc)+/.test('abcabc'); // true
'abcabc'.match(/(?:abc)+/)[0]; // "abcabc"
'abcabc'.match(/(?:abc)+/).length; // 1 (no capture groups)
// Compare to capturing
'abcabc'.match(/(abc)+/); // ["abcabc", "abc"] (has capture)
// Use for alternation
/(?:cat|dog)s?/.test('cats'); // true (s is optional for whole group)
// Numbered backreferences
// Find doubled characters
/(\w)\1/.test('hello'); // true (ll)
'hello'.match(/(\w)\1/)[0]; // "ll"
// Find repeated words
/(\b\w+\b)\s+\1/.test('the the'); // true
// Match balanced quotes
/'([^']*)'/.exec("'hello'")[1]; // "hello"
// HTML attributes
/(\w+)="([^"]*)"/.exec('class="btn"');
// ["class=\"btn\"", "class", "btn"]
// Combining named and numbered groups
const re = /(?<name>\w+):(\d+)/;
const m = 'user:123'.match(re);
m.groups.name; // "user"
m[2]; // "123" (numbered after named)
// Replace with function (named groups)
'John Smith, Jane Doe'.replace(
/(?<first>\w+) (?<last>\w+)/g,
(match, first, last, offset, string, groups) => {
return `${groups.last}, ${groups.first}`;
}
);
// "Smith, John, Doe, Jane"
// Case conversion in replacement
'user_name'.replace(
/_(?<char>\w)/g,
(match, char, offset, string, groups) => {
return groups.char.toUpperCase();
}
);
// "userName"
// Swap parts
'firstName lastName'.replace(
/(?<first>\w+) (?<last>\w+)/,
'$<last> $<first>'
);
// "lastName firstName"
// Optional named groups
const optionalRe = /(?<protocol>https?:\/\/)?(?<domain>[^\/]+)/;
'example.com'.match(optionalRe).groups;
// {protocol: undefined, domain: "example.com"}
'https://example.com'.match(optionalRe).groups;
// {protocol: "https://", domain: "example.com"}
// matchAll with named groups
const text = 'user:123 admin:456';
const matches = text.matchAll(/(?<role>\w+):(?<id>\d+)/g);
for (const match of matches) {
console.log(match.groups.role, match.groups.id);
// "user" "123"
// "admin" "456"
}
#x3C;year>');// "12/17/2025"// Function replacement with named groupsdate.replace(dateRe, (match, y, m, d, offset, str, groups) => { return `${groups.month}/${groups.day}/${groups.year}`;});// Backreference to named groupconst htmlTag = /<(?<tag>\w+)>.*?<\/\k<tag>>/;htmlTag.test('<div>content</div>'); // truehtmlTag.test('<div>content</span>'); // false (tag mismatch)// Find duplicate wordsconst duplicateRe = /\b(?<word>\w+)\s+\k<word>\b/i;duplicateRe.test('the the'); // trueduplicateRe.test('the cat'); // false// Email parsingconst emailRe = /^(?<user>[^\s@]+)@(?<domain>[^\s@]+)\.(?<tld>\w+)$/;const email = 'user@example.com'.match(emailRe);email.groups.user; // "user"email.groups.domain; // "example"email.groups.tld; // "com"// URL parsingconst urlRe = /^(?<protocol>https?):\/\/(?<domain>[^\/]+)(?<path>\/.*)?$/;const url = 'https://example.com/path/to/page'.match(urlRe);url.groups.protocol; // "https"url.groups.domain; // "example.com"url.groups.path; // "/path/to/page"// Phone number formattingconst phoneRe = /(?<area>\d{3})(?<exchange>\d{3})(?<number>\d{4})/;'5551234567'.replace(phoneRe, '(
// Named capture groups
const dateRe = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2025-12-17'.match(dateRe);
match[1]; // "2025" (by index)
match.groups.year; // "2025" (by name)
match.groups.month; // "12"
match.groups.day; // "17"
// Destructuring with named groups
const {groups: {year, month, day}} = '2025-12-17'.match(dateRe);
console.log(year, month, day); // "2025" "12" "17"
// Replace with named groups
const date = '2025-12-17';
date.replace(dateRe, '$<month>/$<day>/$<year>');
// "12/17/2025"
// Function replacement with named groups
date.replace(dateRe, (match, y, m, d, offset, str, groups) => {
return `${groups.month}/${groups.day}/${groups.year}`;
});
// Backreference to named group
const htmlTag = /<(?<tag>\w+)>.*?<\/\k<tag>>/;
htmlTag.test('<div>content</div>'); // true
htmlTag.test('<div>content</span>'); // false (tag mismatch)
// Find duplicate words
const duplicateRe = /\b(?<word>\w+)\s+\k<word>\b/i;
duplicateRe.test('the the'); // true
duplicateRe.test('the cat'); // false
// Email parsing
const emailRe = /^(?<user>[^\s@]+)@(?<domain>[^\s@]+)\.(?<tld>\w+)$/;
const email = 'user@example.com'.match(emailRe);
email.groups.user; // "user"
email.groups.domain; // "example"
email.groups.tld; // "com"
// URL parsing
const urlRe = /^(?<protocol>https?):\/\/(?<domain>[^\/]+)(?<path>\/.*)?$/;
const url = 'https://example.com/path/to/page'.match(urlRe);
url.groups.protocol; // "https"
url.groups.domain; // "example.com"
url.groups.path; // "/path/to/page"
// Phone number formatting
const phoneRe = /(?<area>\d{3})(?<exchange>\d{3})(?<number>\d{4})/;
'5551234567'.replace(phoneRe, '($<area>) $<exchange>-$<number>');
// "(555) 123-4567"
// Non-capturing groups (?:...)
// Group without capturing (performance)
/(?:abc)+/.test('abcabc'); // true
'abcabc'.match(/(?:abc)+/)[0]; // "abcabc"
'abcabc'.match(/(?:abc)+/).length; // 1 (no capture groups)
// Compare to capturing
'abcabc'.match(/(abc)+/); // ["abcabc", "abc"] (has capture)
// Use for alternation
/(?:cat|dog)s?/.test('cats'); // true (s is optional for whole group)
// Numbered backreferences
// Find doubled characters
/(\w)\1/.test('hello'); // true (ll)
'hello'.match(/(\w)\1/)[0]; // "ll"
// Find repeated words
/(\b\w+\b)\s+\1/.test('the the'); // true
// Match balanced quotes
/'([^']*)'/.exec("'hello'")[1]; // "hello"
// HTML attributes
/(\w+)="([^"]*)"/.exec('class="btn"');
// ["class=\"btn\"", "class", "btn"]
// Combining named and numbered groups
const re = /(?<name>\w+):(\d+)/;
const m = 'user:123'.match(re);
m.groups.name; // "user"
m[2]; // "123" (numbered after named)
// Replace with function (named groups)
'John Smith, Jane Doe'.replace(
/(?<first>\w+) (?<last>\w+)/g,
(match, first, last, offset, string, groups) => {
return `${groups.last}, ${groups.first}`;
}
);
// "Smith, John, Doe, Jane"
// Case conversion in replacement
'user_name'.replace(
/_(?<char>\w)/g,
(match, char, offset, string, groups) => {
return groups.char.toUpperCase();
}
);
// "userName"
// Swap parts
'firstName lastName'.replace(
/(?<first>\w+) (?<last>\w+)/,
'$<last> $<first>'
);
// "lastName firstName"
// Optional named groups
const optionalRe = /(?<protocol>https?:\/\/)?(?<domain>[^\/]+)/;
'example.com'.match(optionalRe).groups;
// {protocol: undefined, domain: "example.com"}
'https://example.com'.match(optionalRe).groups;
// {protocol: "https://", domain: "example.com"}
// matchAll with named groups
const text = 'user:123 admin:456';
const matches = text.matchAll(/(?<role>\w+):(?<id>\d+)/g);
for (const match of matches) {
console.log(match.groups.role, match.groups.id);
// "user" "123"
// "admin" "456"
}
#x3C;area>)
// Named capture groups
const dateRe = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2025-12-17'.match(dateRe);
match[1]; // "2025" (by index)
match.groups.year; // "2025" (by name)
match.groups.month; // "12"
match.groups.day; // "17"
// Destructuring with named groups
const {groups: {year, month, day}} = '2025-12-17'.match(dateRe);
console.log(year, month, day); // "2025" "12" "17"
// Replace with named groups
const date = '2025-12-17';
date.replace(dateRe, '$<month>/$<day>/$<year>');
// "12/17/2025"
// Function replacement with named groups
date.replace(dateRe, (match, y, m, d, offset, str, groups) => {
return `${groups.month}/${groups.day}/${groups.year}`;
});
// Backreference to named group
const htmlTag = /<(?<tag>\w+)>.*?<\/\k<tag>>/;
htmlTag.test('<div>content</div>'); // true
htmlTag.test('<div>content</span>'); // false (tag mismatch)
// Find duplicate words
const duplicateRe = /\b(?<word>\w+)\s+\k<word>\b/i;
duplicateRe.test('the the'); // true
duplicateRe.test('the cat'); // false
// Email parsing
const emailRe = /^(?<user>[^\s@]+)@(?<domain>[^\s@]+)\.(?<tld>\w+)$/;
const email = 'user@example.com'.match(emailRe);
email.groups.user; // "user"
email.groups.domain; // "example"
email.groups.tld; // "com"
// URL parsing
const urlRe = /^(?<protocol>https?):\/\/(?<domain>[^\/]+)(?<path>\/.*)?$/;
const url = 'https://example.com/path/to/page'.match(urlRe);
url.groups.protocol; // "https"
url.groups.domain; // "example.com"
url.groups.path; // "/path/to/page"
// Phone number formatting
const phoneRe = /(?<area>\d{3})(?<exchange>\d{3})(?<number>\d{4})/;
'5551234567'.replace(phoneRe, '($<area>) $<exchange>-$<number>');
// "(555) 123-4567"
// Non-capturing groups (?:...)
// Group without capturing (performance)
/(?:abc)+/.test('abcabc'); // true
'abcabc'.match(/(?:abc)+/)[0]; // "abcabc"
'abcabc'.match(/(?:abc)+/).length; // 1 (no capture groups)
// Compare to capturing
'abcabc'.match(/(abc)+/); // ["abcabc", "abc"] (has capture)
// Use for alternation
/(?:cat|dog)s?/.test('cats'); // true (s is optional for whole group)
// Numbered backreferences
// Find doubled characters
/(\w)\1/.test('hello'); // true (ll)
'hello'.match(/(\w)\1/)[0]; // "ll"
// Find repeated words
/(\b\w+\b)\s+\1/.test('the the'); // true
// Match balanced quotes
/'([^']*)'/.exec("'hello'")[1]; // "hello"
// HTML attributes
/(\w+)="([^"]*)"/.exec('class="btn"');
// ["class=\"btn\"", "class", "btn"]
// Combining named and numbered groups
const re = /(?<name>\w+):(\d+)/;
const m = 'user:123'.match(re);
m.groups.name; // "user"
m[2]; // "123" (numbered after named)
// Replace with function (named groups)
'John Smith, Jane Doe'.replace(
/(?<first>\w+) (?<last>\w+)/g,
(match, first, last, offset, string, groups) => {
return `${groups.last}, ${groups.first}`;
}
);
// "Smith, John, Doe, Jane"
// Case conversion in replacement
'user_name'.replace(
/_(?<char>\w)/g,
(match, char, offset, string, groups) => {
return groups.char.toUpperCase();
}
);
// "userName"
// Swap parts
'firstName lastName'.replace(
/(?<first>\w+) (?<last>\w+)/,
'$<last> $<first>'
);
// "lastName firstName"
// Optional named groups
const optionalRe = /(?<protocol>https?:\/\/)?(?<domain>[^\/]+)/;
'example.com'.match(optionalRe).groups;
// {protocol: undefined, domain: "example.com"}
'https://example.com'.match(optionalRe).groups;
// {protocol: "https://", domain: "example.com"}
// matchAll with named groups
const text = 'user:123 admin:456';
const matches = text.matchAll(/(?<role>\w+):(?<id>\d+)/g);
for (const match of matches) {
console.log(match.groups.role, match.groups.id);
// "user" "123"
// "admin" "456"
}
#x3C;exchange>-
// Named capture groups
const dateRe = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2025-12-17'.match(dateRe);
match[1]; // "2025" (by index)
match.groups.year; // "2025" (by name)
match.groups.month; // "12"
match.groups.day; // "17"
// Destructuring with named groups
const {groups: {year, month, day}} = '2025-12-17'.match(dateRe);
console.log(year, month, day); // "2025" "12" "17"
// Replace with named groups
const date = '2025-12-17';
date.replace(dateRe, '$<month>/$<day>/$<year>');
// "12/17/2025"
// Function replacement with named groups
date.replace(dateRe, (match, y, m, d, offset, str, groups) => {
return `${groups.month}/${groups.day}/${groups.year}`;
});
// Backreference to named group
const htmlTag = /<(?<tag>\w+)>.*?<\/\k<tag>>/;
htmlTag.test('<div>content</div>'); // true
htmlTag.test('<div>content</span>'); // false (tag mismatch)
// Find duplicate words
const duplicateRe = /\b(?<word>\w+)\s+\k<word>\b/i;
duplicateRe.test('the the'); // true
duplicateRe.test('the cat'); // false
// Email parsing
const emailRe = /^(?<user>[^\s@]+)@(?<domain>[^\s@]+)\.(?<tld>\w+)$/;
const email = 'user@example.com'.match(emailRe);
email.groups.user; // "user"
email.groups.domain; // "example"
email.groups.tld; // "com"
// URL parsing
const urlRe = /^(?<protocol>https?):\/\/(?<domain>[^\/]+)(?<path>\/.*)?$/;
const url = 'https://example.com/path/to/page'.match(urlRe);
url.groups.protocol; // "https"
url.groups.domain; // "example.com"
url.groups.path; // "/path/to/page"
// Phone number formatting
const phoneRe = /(?<area>\d{3})(?<exchange>\d{3})(?<number>\d{4})/;
'5551234567'.replace(phoneRe, '($<area>) $<exchange>-$<number>');
// "(555) 123-4567"
// Non-capturing groups (?:...)
// Group without capturing (performance)
/(?:abc)+/.test('abcabc'); // true
'abcabc'.match(/(?:abc)+/)[0]; // "abcabc"
'abcabc'.match(/(?:abc)+/).length; // 1 (no capture groups)
// Compare to capturing
'abcabc'.match(/(abc)+/); // ["abcabc", "abc"] (has capture)
// Use for alternation
/(?:cat|dog)s?/.test('cats'); // true (s is optional for whole group)
// Numbered backreferences
// Find doubled characters
/(\w)\1/.test('hello'); // true (ll)
'hello'.match(/(\w)\1/)[0]; // "ll"
// Find repeated words
/(\b\w+\b)\s+\1/.test('the the'); // true
// Match balanced quotes
/'([^']*)'/.exec("'hello'")[1]; // "hello"
// HTML attributes
/(\w+)="([^"]*)"/.exec('class="btn"');
// ["class=\"btn\"", "class", "btn"]
// Combining named and numbered groups
const re = /(?<name>\w+):(\d+)/;
const m = 'user:123'.match(re);
m.groups.name; // "user"
m[2]; // "123" (numbered after named)
// Replace with function (named groups)
'John Smith, Jane Doe'.replace(
/(?<first>\w+) (?<last>\w+)/g,
(match, first, last, offset, string, groups) => {
return `${groups.last}, ${groups.first}`;
}
);
// "Smith, John, Doe, Jane"
// Case conversion in replacement
'user_name'.replace(
/_(?<char>\w)/g,
(match, char, offset, string, groups) => {
return groups.char.toUpperCase();
}
);
// "userName"
// Swap parts
'firstName lastName'.replace(
/(?<first>\w+) (?<last>\w+)/,
'$<last> $<first>'
);
// "lastName firstName"
// Optional named groups
const optionalRe = /(?<protocol>https?:\/\/)?(?<domain>[^\/]+)/;
'example.com'.match(optionalRe).groups;
// {protocol: undefined, domain: "example.com"}
'https://example.com'.match(optionalRe).groups;
// {protocol: "https://", domain: "example.com"}
// matchAll with named groups
const text = 'user:123 admin:456';
const matches = text.matchAll(/(?<role>\w+):(?<id>\d+)/g);
for (const match of matches) {
console.log(match.groups.role, match.groups.id);
// "user" "123"
// "admin" "456"
}
#x3C;number>');// "(555) 123-4567"// Non-capturing groups (?:...)// Group without capturing (performance)/(?:abc)+/.test('abcabc'); // true'abcabc'.match(/(?:abc)+/)[0]; // "abcabc"'abcabc'.match(/(?:abc)+/).length; // 1 (no capture groups)// Compare to capturing'abcabc'.match(/(abc)+/); // ["abcabc", "abc"] (has capture)// Use for alternation/(?:cat|dog)s?/.test('cats'); // true (s is optional for whole group)// Numbered backreferences// Find doubled characters/(\w)\1/.test('hello'); // true (ll)'hello'.match(/(\w)\1/)[0]; // "ll"// Find repeated words/(\b\w+\b)\s+\1/.test('the the'); // true// Match balanced quotes/'([^']*)'/.exec("'hello'")[1]; // "hello"// HTML attributes/(\w+)="([^"]*)"/.exec('class="btn"');// ["class=\"btn\"", "class", "btn"]// Combining named and numbered groupsconst re = /(?<name>\w+):(\d+)/;const m = 'user:123'.match(re);m.groups.name; // "user"m[2]; // "123" (numbered after named)// Replace with function (named groups)'John Smith, Jane Doe'.replace( /(?<first>\w+) (?<last>\w+)/g, (match, first, last, offset, string, groups) => { return `${groups.last}, ${groups.first}`; });// "Smith, John, Doe, Jane"// Case conversion in replacement'user_name'.replace( /_(?<char>\w)/g, (match, char, offset, string, groups) => { return groups.char.toUpperCase(); });// "userName"// Swap parts'firstName lastName'.replace( /(?<first>\w+) (?<last>\w+)/, '
// Named capture groups
const dateRe = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2025-12-17'.match(dateRe);
match[1]; // "2025" (by index)
match.groups.year; // "2025" (by name)
match.groups.month; // "12"
match.groups.day; // "17"
// Destructuring with named groups
const {groups: {year, month, day}} = '2025-12-17'.match(dateRe);
console.log(year, month, day); // "2025" "12" "17"
// Replace with named groups
const date = '2025-12-17';
date.replace(dateRe, '$<month>/$<day>/$<year>');
// "12/17/2025"
// Function replacement with named groups
date.replace(dateRe, (match, y, m, d, offset, str, groups) => {
return `${groups.month}/${groups.day}/${groups.year}`;
});
// Backreference to named group
const htmlTag = /<(?<tag>\w+)>.*?<\/\k<tag>>/;
htmlTag.test('<div>content</div>'); // true
htmlTag.test('<div>content</span>'); // false (tag mismatch)
// Find duplicate words
const duplicateRe = /\b(?<word>\w+)\s+\k<word>\b/i;
duplicateRe.test('the the'); // true
duplicateRe.test('the cat'); // false
// Email parsing
const emailRe = /^(?<user>[^\s@]+)@(?<domain>[^\s@]+)\.(?<tld>\w+)$/;
const email = 'user@example.com'.match(emailRe);
email.groups.user; // "user"
email.groups.domain; // "example"
email.groups.tld; // "com"
// URL parsing
const urlRe = /^(?<protocol>https?):\/\/(?<domain>[^\/]+)(?<path>\/.*)?$/;
const url = 'https://example.com/path/to/page'.match(urlRe);
url.groups.protocol; // "https"
url.groups.domain; // "example.com"
url.groups.path; // "/path/to/page"
// Phone number formatting
const phoneRe = /(?<area>\d{3})(?<exchange>\d{3})(?<number>\d{4})/;
'5551234567'.replace(phoneRe, '($<area>) $<exchange>-$<number>');
// "(555) 123-4567"
// Non-capturing groups (?:...)
// Group without capturing (performance)
/(?:abc)+/.test('abcabc'); // true
'abcabc'.match(/(?:abc)+/)[0]; // "abcabc"
'abcabc'.match(/(?:abc)+/).length; // 1 (no capture groups)
// Compare to capturing
'abcabc'.match(/(abc)+/); // ["abcabc", "abc"] (has capture)
// Use for alternation
/(?:cat|dog)s?/.test('cats'); // true (s is optional for whole group)
// Numbered backreferences
// Find doubled characters
/(\w)\1/.test('hello'); // true (ll)
'hello'.match(/(\w)\1/)[0]; // "ll"
// Find repeated words
/(\b\w+\b)\s+\1/.test('the the'); // true
// Match balanced quotes
/'([^']*)'/.exec("'hello'")[1]; // "hello"
// HTML attributes
/(\w+)="([^"]*)"/.exec('class="btn"');
// ["class=\"btn\"", "class", "btn"]
// Combining named and numbered groups
const re = /(?<name>\w+):(\d+)/;
const m = 'user:123'.match(re);
m.groups.name; // "user"
m[2]; // "123" (numbered after named)
// Replace with function (named groups)
'John Smith, Jane Doe'.replace(
/(?<first>\w+) (?<last>\w+)/g,
(match, first, last, offset, string, groups) => {
return `${groups.last}, ${groups.first}`;
}
);
// "Smith, John, Doe, Jane"
// Case conversion in replacement
'user_name'.replace(
/_(?<char>\w)/g,
(match, char, offset, string, groups) => {
return groups.char.toUpperCase();
}
);
// "userName"
// Swap parts
'firstName lastName'.replace(
/(?<first>\w+) (?<last>\w+)/,
'$<last> $<first>'
);
// "lastName firstName"
// Optional named groups
const optionalRe = /(?<protocol>https?:\/\/)?(?<domain>[^\/]+)/;
'example.com'.match(optionalRe).groups;
// {protocol: undefined, domain: "example.com"}
'https://example.com'.match(optionalRe).groups;
// {protocol: "https://", domain: "example.com"}
// matchAll with named groups
const text = 'user:123 admin:456';
const matches = text.matchAll(/(?<role>\w+):(?<id>\d+)/g);
for (const match of matches) {
console.log(match.groups.role, match.groups.id);
// "user" "123"
// "admin" "456"
}
#x3C;last>
// Named capture groups
const dateRe = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2025-12-17'.match(dateRe);
match[1]; // "2025" (by index)
match.groups.year; // "2025" (by name)
match.groups.month; // "12"
match.groups.day; // "17"
// Destructuring with named groups
const {groups: {year, month, day}} = '2025-12-17'.match(dateRe);
console.log(year, month, day); // "2025" "12" "17"
// Replace with named groups
const date = '2025-12-17';
date.replace(dateRe, '$<month>/$<day>/$<year>');
// "12/17/2025"
// Function replacement with named groups
date.replace(dateRe, (match, y, m, d, offset, str, groups) => {
return `${groups.month}/${groups.day}/${groups.year}`;
});
// Backreference to named group
const htmlTag = /<(?<tag>\w+)>.*?<\/\k<tag>>/;
htmlTag.test('<div>content</div>'); // true
htmlTag.test('<div>content</span>'); // false (tag mismatch)
// Find duplicate words
const duplicateRe = /\b(?<word>\w+)\s+\k<word>\b/i;
duplicateRe.test('the the'); // true
duplicateRe.test('the cat'); // false
// Email parsing
const emailRe = /^(?<user>[^\s@]+)@(?<domain>[^\s@]+)\.(?<tld>\w+)$/;
const email = 'user@example.com'.match(emailRe);
email.groups.user; // "user"
email.groups.domain; // "example"
email.groups.tld; // "com"
// URL parsing
const urlRe = /^(?<protocol>https?):\/\/(?<domain>[^\/]+)(?<path>\/.*)?$/;
const url = 'https://example.com/path/to/page'.match(urlRe);
url.groups.protocol; // "https"
url.groups.domain; // "example.com"
url.groups.path; // "/path/to/page"
// Phone number formatting
const phoneRe = /(?<area>\d{3})(?<exchange>\d{3})(?<number>\d{4})/;
'5551234567'.replace(phoneRe, '($<area>) $<exchange>-$<number>');
// "(555) 123-4567"
// Non-capturing groups (?:...)
// Group without capturing (performance)
/(?:abc)+/.test('abcabc'); // true
'abcabc'.match(/(?:abc)+/)[0]; // "abcabc"
'abcabc'.match(/(?:abc)+/).length; // 1 (no capture groups)
// Compare to capturing
'abcabc'.match(/(abc)+/); // ["abcabc", "abc"] (has capture)
// Use for alternation
/(?:cat|dog)s?/.test('cats'); // true (s is optional for whole group)
// Numbered backreferences
// Find doubled characters
/(\w)\1/.test('hello'); // true (ll)
'hello'.match(/(\w)\1/)[0]; // "ll"
// Find repeated words
/(\b\w+\b)\s+\1/.test('the the'); // true
// Match balanced quotes
/'([^']*)'/.exec("'hello'")[1]; // "hello"
// HTML attributes
/(\w+)="([^"]*)"/.exec('class="btn"');
// ["class=\"btn\"", "class", "btn"]
// Combining named and numbered groups
const re = /(?<name>\w+):(\d+)/;
const m = 'user:123'.match(re);
m.groups.name; // "user"
m[2]; // "123" (numbered after named)
// Replace with function (named groups)
'John Smith, Jane Doe'.replace(
/(?<first>\w+) (?<last>\w+)/g,
(match, first, last, offset, string, groups) => {
return `${groups.last}, ${groups.first}`;
}
);
// "Smith, John, Doe, Jane"
// Case conversion in replacement
'user_name'.replace(
/_(?<char>\w)/g,
(match, char, offset, string, groups) => {
return groups.char.toUpperCase();
}
);
// "userName"
// Swap parts
'firstName lastName'.replace(
/(?<first>\w+) (?<last>\w+)/,
'$<last> $<first>'
);
// "lastName firstName"
// Optional named groups
const optionalRe = /(?<protocol>https?:\/\/)?(?<domain>[^\/]+)/;
'example.com'.match(optionalRe).groups;
// {protocol: undefined, domain: "example.com"}
'https://example.com'.match(optionalRe).groups;
// {protocol: "https://", domain: "example.com"}
// matchAll with named groups
const text = 'user:123 admin:456';
const matches = text.matchAll(/(?<role>\w+):(?<id>\d+)/g);
for (const match of matches) {
console.log(match.groups.role, match.groups.id);
// "user" "123"
// "admin" "456"
}
#x3C;first>');// "lastName firstName"// Optional named groupsconst optionalRe = /(?<protocol>https?:\/\/)?(?<domain>[^\/]+)/;'example.com'.match(optionalRe).groups;// {protocol: undefined, domain: "example.com"}'https://example.com'.match(optionalRe).groups;// {protocol: "https://", domain: "example.com"}// matchAll with named groupsconst text = 'user:123 admin:456';const matches = text.matchAll(/(?<role>\w+):(?<id>\d+)/g);for (const match of matches) { console.log(match.groups.role, match.groups.id); // "user" "123" // "admin" "456"}
Note: Named groups improve readability and maintainability. Use (?:...) for
grouping without capturing (better performance). Backreferences \k<name> or \1
match same text as group.
Section 11 Summary
Creation: Literal /pattern/flags for static (compile-time);
constructor new RegExp(str, flags) for dynamic (escape backslashes: '\\d')
Flags:g (global), i (case-insensitive),
m (multiline ^$), s (dotAll), u (Unicode), y (sticky),
d (indices); g makes regex stateful
Methods:test() boolean; exec() details + loop
with g; match() simple/all; matchAll() iterator with details (requires g)
String methods:replace/replaceAll modify; split
divide (includes captures); search find index; use $1 $<name> in replacement