Regex
02 / 03

Regex Fundamentals

Regex Fundamentals

Regular expressions are patterns for matching character combinations in strings. In JavaScript, regex literals are written as /pattern/flags or constructed via new RegExp(pattern, flags).

Character Classes & Anchors

# Character classes
.        any character except newline
\d       digit [0-9]
\D       non-digit
\w       word char [a-zA-Z0-9_]
\W       non-word char
\s       whitespace (space, tab, newline)
\S       non-whitespace
[abc]    any of a, b, c
[^abc]   none of a, b, c
[a-z]    range a to z
[a-zA-Z0-9] alphanumeric

# Anchors
^        start of string (or line with m flag)
$        end of string (or line with m flag)
\b       word boundary  — \bcat\b matches "cat" not "catch"
\B       non-word boundary

# Quantifiers
*        0 or more (greedy)
+        1 or more (greedy)
?        0 or 1
{n}      exactly n
{n,}     n or more
{n,m}    between n and m
*?  +?  ??  {n,m}?   non-greedy (lazy) versions

Groups & Lookahead / Lookbehind

# Groups
(abc)          capturing group
(?:abc)        non-capturing group (no capture overhead)
(?<name>abc)   named capture group
a|b            alternation: a or b
\1             backreference to group 1

# Lookahead & lookbehind (zero-width assertions)
(?=abc)   positive lookahead  — position must be followed by abc
(?!abc)   negative lookahead  — position must NOT be followed by abc
(?<=abc)  positive lookbehind — position must be preceded by abc
(?<!abc)  negative lookbehind — position must NOT be preceded by abc

# Examples
\d+(?= dollars)   matches a number only if followed by " dollars"
(?<!\d)\d{4}      matches 4-digit number NOT preceded by a digit

JavaScript Regex API

// test() — returns boolean
/^\d{4}$/.test('2024')            // true
/^\d{4}$/.test('abc')             // false

// match() — first match (or all matches with /g flag)
'hello world'.match(/\w+/)        // ['hello', index: 0, input: ...]
'hello world'.match(/\w+/g)       // ['hello', 'world']

// matchAll() — iterator over all matches (requires /g flag)
const re = /(?<year>\d{4})-(?<month>\d{2})/g;
for (const m of '2024-01 and 2025-06'.matchAll(re)) {
  console.log(m.groups.year, m.groups.month);
}

// replace() / replaceAll()
'foo bar'.replace(/\s+/, '-')          // 'foo-bar' (first only)
'foo bar baz'.replace(/\s+/g, '-')     // 'foo-bar-baz'
// Replace with function (match, group1, offset, string)
'hello world'.replace(/(\w+)/g, (match) => match.toUpperCase())  // 'HELLO WORLD'

// split()
'one, two,  three'.split(/,\s*/)   // ['one', 'two', 'three']

// exec() — stateful; advances lastIndex with /g
const pattern = /\d+/g;
let result;
while ((result = pattern.exec('1 fish 2 fish')) !== null) {
  console.log(result[0], 'at index', result.index);
}

Named Capture Groups

// Named groups — access via match.groups
const dateRe = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const m = '2024-03-15'.match(dateRe);
const { year, month, day } = m.groups;  // '2024', '03', '15'

// Named groups in replace()
'John Smith'.replace(
  /(?<first>\w+) (?<last>\w+)/,
  '$<last>, $<first>'   // 'Smith, John'
);

// Named groups in replaceAll with function
'2024-01-15 and 2025-06-20'.replaceAll(
  /(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/g,
  (_, y, mo, d) => `${mo}/${d}/${y}`
);
// '01/15/2024 and 06/20/2025'

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free