JSadvancedes2020

Modern regular expressions

Regex grew up.

Named groups, matchAll, lookbehind, the d flag, and callback replacements turn regex from write-only line noise into readable, structured parsing.

Name your captures

Numbered groups (match[1], match[2]) are positional and fragile β€” insert a group and every index shifts. Named capture groups (?<year>\d{4}) land in match.groups.year, so your parsing code reads like the data it extracts and survives pattern edits.

Iterate every match with matchAll

String.prototype.matchAll returns an iterator of full match objects β€” each with its index, capture groups, and named groups. Unlike String.replace with a global flag, you get the whole match shape, and unlike regex.exec in a loop you don't manage lastIndex by hand. The regex must carry the g flag.

Look around without consuming

Lookbehind (?<=...) and lookahead (?=...) assert that text exists before or after the cursor without including it in the match. That makes them perfect for "the number after $" or "the digits before kg" β€” you match the payload, not the marker.

The d flag: where, not just what

The d (hasIndices) flag adds a .indices array to each match giving [start, end] offsets for the whole match and every group β€” including named ones under indices.groups. Use it when you need to highlight or splice the source text, not just read the captured value.

Callbacks and capturing splits

replace/replaceAll accept a function: it receives the match, each group, the offset, and the source, and returns the replacement β€” arbitrary logic per match, no template-string limits. And split with a regex that captures keeps the delimiters in the output array, so you can tokenise while preserving what you split on.

Try it 5 examples

Named capture groups

JSintro
Press Run to execute

m.groups yields { year, month, day } so y=2026 m=06 d=19 reads straight from the names, and the $<name> syntax reorders the parts into 19/06/2026 without a single numeric index.