Guide// Developer

Regex Cheat Sheet — The Patterns You'll Actually Use

Regex Cheat Sheet — The Patterns You'll Actually Use
The short answer

This is the regex reference you keep open while you work: the syntax that comes up daily, a set of copy-ready patterns, and — the part most cheat sheets skip — the traps that waste your afternoon. Test anything here live in the free Regex Tester, which highlights matches as you type, breaks out your capture groups, and previews replacements. (Everything below is JavaScript/ECMAScript flavor; see the cross-language note at the end.)

On this page

Character classes

Token Matches
. Any character except newline
\d / \D A digit [0-9] / a non-digit
\w / \W A word char [A-Za-z0-9_] / a non-word char
\s / \S Whitespace / non-whitespace
[abc] Any one of a, b, c
[^abc] Any char except a, b, c
[a-z] A range (lowercase letter)

Anchors

Token Matches
^ Start of string (or line, with the m flag)
$ End of string (or line, with m)
\b / \B A word boundary / a non-boundary

\b is the one people forget — it's why \bcat\b matches "cat" but not "category."

Quantifiers (and the greedy-vs-lazy trap)

Token Means
* 0 or more
+ 1 or more
? 0 or 1 (optional)
{n} Exactly n
{n,} n or more
{n,m} Between n and m
*? +? ?? The lazy versions (match as few as possible)

By default quantifiers are greedy — they grab as much as they can. This is the classic bug: on <b>hello</b>, the pattern <.*> matches the whole string (first < to last >), while <.*?> (lazy) matches just <b>. Rule: when matching between delimiters — quotes, brackets, tags — use the lazy version.

Groups and alternation

Token Means
(...) Capture group (extract it later)
(?:...) Non-capturing group (group without storing)
(?<name>...) Named capture group
(a|b) Alternation — a or b
\1, \k<name> Backreference to a captured group

If you don't need to extract a group, make it non-capturing (?:...) — it's cleaner and slightly faster.

Lookarounds (zero-width — they match a position, not characters)

Token Means
(?=...) Positive lookahead — followed by
(?!...) Negative lookahead — not followed by
(?<=...) Positive lookbehind — preceded by
(?<!...) Negative lookbehind — not preceded by

Example: (?<=\$)\d+ grabs 199 from $199 without including the $. Lookarounds are how password rules work too: (?=.*\d) means "contains a digit somewhere" without consuming anything.

Flags

Flag Effect
g Global — find all matches, not just the first
i Case-insensitive
m Multiline — ^/$ match line starts/ends
s Dotall — . also matches newlines
u Unicode mode
y Sticky — match from lastIndex only

The g flag is the one that surprises people: without it you get only the first match; with it you get them all. The Regex Tester has toggle buttons for every flag, so you can flip g/i/m and watch the matches change.

Ready-to-use patterns (test before you ship)

Need Pattern
Digits only ^\d+$
Hex color ^#?([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$
US ZIP ^\d{5}(-\d{4})?$
ISO date (YYYY-MM-DD) ^\d{4}-\d{2}-\d{2}$
Slug ^[a-z0-9]+(?:-[a-z0-9]+)*$
Strong password (8+, upper, digit, symbol) ^(?=.*[A-Z])(?=.*\d)(?=.*[^\w\s]).{8,}$
Duplicated word \b(\w+)\s+\1\b

On matching an email: you'll see a "perfect email regex" everywhere — don't trust it. A fully RFC-correct email regex is monstrous and still rejects valid addresses. For real validation, a loose check like ^[^@\s]+@[^@\s]+\.[^@\s]+$ plus actually sending a confirmation email beats any clever pattern. Regex tells you it looks like an email, not that it works.

The gotchas that cost you time

  • Escape special characters to match them literally: a literal dot is \., a literal ? is \?. Forgetting this is the #1 regex bug.
  • Catastrophic backtracking (ReDoS): nested quantifiers like (a+)+b can hang on long non-matching input — a real denial-of-service risk on user input. Avoid nesting quantifiers; rewrite or anchor instead.
  • Don't parse HTML, XML, or JSON with regex. They're nested/recursive; regex isn't built for that and will break on edge cases. Use a real parser — for JSON, the JSON Formatter validates far more reliably than any pattern.
  • Build incrementally. Test each piece in the Regex Tester before combining — a 60-character pattern you wrote in one go is a debugging nightmare.

Is regex the same in every language?

The core — character classes, quantifiers, anchors, basic groups — is consistent. The advanced bits differ: lookbehind, named groups, Unicode escapes, and flag syntax vary between JavaScript, Python (re), Java, Go, and PCRE. This cheat sheet is JavaScript flavor; if you're in another language, the basics carry over but check its docs for the fancy features.

Frequently asked

What does `\d`, `\w`, and `\b` mean?
`\d` matches a digit (0–9), `\w` matches a word character (letters, digits, underscore), and `\b` matches a word boundary — the position between a word char and a non-word char. So `\bcat\b` matches "cat" as a whole word but not inside "category."
What's the difference between greedy and lazy quantifiers?
Greedy quantifiers (`*`, `+`) match as much as possible; lazy ones (`*?`, `+?`) match as little as possible. On `<b>hi</b>`, `<.*>` greedily matches the whole string, while `<.*?>` matches just `<b>`. Use lazy when matching between delimiters.
What does the `g` flag do?
It makes the regex global — it finds *all* matches in the string instead of stopping at the first. Without `g`, methods like `match()` return only the first hit. Toggle it in the Regex Tester to see the difference instantly.
How do I match an email with regex?
A practical check is `^[^@\s]+@[^@\s]+\.[^@\s]+$`, but know that no regex perfectly validates email — the full spec is enormous and still allows odd valid addresses. Use a loose pattern for a sanity check and confirm with a real verification email.
What is a capture group?
Parentheses `(...)` that "capture" the matched text so you can extract or reference it. `(\d{4})-(\d{2})` on "2026-03" captures "2026" and "03" as groups 1 and 2. Use `(?:...)` when you want to group without capturing.
What's a lookahead vs a lookbehind?
Both are zero-width assertions that check context without consuming characters. A lookahead `(?=...)` checks what comes *after* the current position; a lookbehind `(?<=...)` checks what comes *before*. Example: `(?<=\$)\d+` matches the number after a `$` without including the `$`.
Is regex the same in every language?
The basics are; the advanced features aren't. Lookbehind, named groups, Unicode handling, and flags differ across JavaScript, Python, Java, Go, and PCRE. This sheet is JavaScript flavor — verify advanced syntax against your language's docs.
Ready? Open Regex Tester Use it free →