JavaScript Regex Cheat Sheet

Every JavaScript regex token that matters — anchors, classes, quantifiers, groups, lookarounds, flags and substitutions — in scannable tables.

Published 2026-09-25

This is the JavaScript dialect — what new RegExp() in a browser or Node.js understands. Most of it is shared with PCRE and Python, but the differences (ASCII \w, no possessive quantifiers, the u flag changing what’s legal) are marked where they matter. Try any row live on the tester home page.

Anchors — positions, not characters

Token Matches JS notes
^ start of input with m: also after every \n
$ end of input with m: also before every \n; without it, still allows one final \n
\b word boundary between \w and non-\w — matches nothing itself
\B non-word-boundary everywhere \b doesn’t

There is no \A or \z in JavaScript — ^/$ are all you get, which is why the m flag changes their meaning rather than adding separate tokens.

Character classes

Token Matches Notes
. any char except line terminators with s: truly anything
\d \D digit / non-digit [0-9] — ASCII only, always
\w \W word / non-word [a-zA-Z0-9_] — stays ASCII even under u
\s \S whitespace / non-whitespace includes \n \t \r \f \v and Unicode spaces
[abc] one of a, b, c ] ^ - \ need care inside
[^abc] one char NOT a, b, c negation
[a-z] range [0-9a-fA-F] is the hex idiom
\p{L} any Unicode letter needs the u flag — also \p{N}, \p{Emoji}, \p{Script=Greek}

Quantifiers — and the laziness toggle

Token Meaning Greedy vs lazy
* 0 or more greedy: max first, back off if needed
+ 1 or more same
? optional greedy — prefers “present”
{n} exactly n
{n,} n or more unbounded — watch these inside loops
{n,m} between n and m

Append ? to any quantifier to make it lazy (match as little as possible): *?, +?, ??, {2,}?. JavaScript has no possessive quantifiers (a++) and no atomic groups ((?>…)) — the constructs other engines offer to kill backtracking. That’s exactly why catastrophic backtracking is a JavaScript problem, not just a theory problem.

Groups — capturing, not capturing, named

Syntax What it does
(abc) capture group — saves matched text as group n (\n, $n, match[n])
(?:abc) non-capturing — grouping only, nothing saved
(?<name>abc) named capture — match.groups.name, \k<name>, $<name> in replace
\1\9 backreference — match the same text group n already captured
a|b alternation — left branch tried first, order matters

Lookarounds — zero-width requirements

Syntax Meaning
x(?=y) x only if followed by y (lookahead, consumes nothing)
x(?!y) x only if NOT followed by y
(?<=y)x x only if preceded by y (lookbehind, ES2018)
(?<!y)x x only if NOT preceded by y

Lookbehind is the newest and the one to check if you ship to older environments. The classic use: \d+(?= dollars) matches the number in 100 dollars without capturing the unit.

Flags — what each one actually changes

Flag Name Effect
g global find all matches, not just the first — also makes exec/test stateful via lastIndex
i ignoreCase case folding (respects u Unicode folding)
m multiline ^/$ match per line
s dotAll . matches line terminators too
u unicode code-point semantics, \p{}, \u{}, stricter syntax
y sticky match must start exactly at lastIndex — no skipping ahead
d hasIndices match objects carry [start,end] per group (ES2022)

Replace substitutions — the $ tokens

Token Inserts
$$ a literal $
$& the whole match
$` text before the match
$' text after the match
$1$99 capture group text
$<name> named group text

'2026-09-24'.replace(/(\d+)-(\d+)-(\d+)/, '$3/$2/$1')'24/09/2026'. Try it in the replace mode on the tester.

Idioms worth memorizing

  • [\s\S] — “any character including newlines” without the s flag
  • [^"]* — run of non-quote chars (safer than .*? when you know the delimiter)
  • \bword\b — whole-word match (\b fails next to punctuation, not inside \w)
  • (?<=\d)px — a unit that must follow a digit, excluded from the match
  • ^(?:.*\n){3} — “exactly the first three lines” is not this — but it shows how groups compose

When in doubt, paste the pattern into the explain mode — it reads every token back to you in English before you ship it.

Frequently asked questions

Is \w the same as [a-zA-Z0-9_]?

Almost — in JavaScript without the u flag, \w is exactly [a-zA-Z0-9_]: ASCII only, so it won't match é, ü or Chinese characters. With the u flag it stays ASCII (unlike some engines where \w goes Unicode) — for real Unicode letters you need \p{L} with the u flag, e.g. /[\p{L}\p{N}_]/u.

Why doesn't my dot match newlines?

It never did — . in JavaScript means "any character except a line terminator" (\n, \r, \u2028, \u2029). Add the s flag (dotAll, ES2018) to make . truly mean anything, or use the idiom [\s\S] which has worked forever.

What's the difference between *? and +?

One is about how MUCH to match, the other about HOW. + is greedy: take as many as possible, back off only if the rest of the pattern fails. *? is lazy: take as few as possible, extend only when forced. <.+> on '' grabs '' in one match; <.+?> grabs '' then ''.