Cheatsheet

Regex Cheatsheet

# Regex Cheatsheet

Regular expressions describe text patterns for matching, extracting, and replacing. This sheet covers the syntax shared by JavaScript, PCRE (PHP, most CLI grep flavors) and Python's re, and calls out the handful of places those engines disagree — the source of most "why doesn't this regex work" bugs.

Quick reference

Character classes

Syntax Matches Example
`.` Any char except newline (unless `s` flag) `a.c` matches `abc`
`\d` Digit `[0-9]` `\d{3}` matches `123`
`\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]` Not a, b, or c
`[a-z]` Range a to z
`\b` Word boundary (zero-width) `\bcat\b` won't match `catalog`
`\B` Not a word boundary

Anchors and quantifiers

Syntax Meaning
`^` Start of string (or line, with `m` flag)
`$` End of string (or line, with `m` flag)
`*` 0 or more (greedy)
`+` 1 or more (greedy)
`?` 0 or 1 (greedy); also makes a quantifier lazy: `*?`, `+?`
`{n}` Exactly n
`{n,}` n or more
`{n,m}` Between n and m

Groups and flags

Syntax Meaning
`(...)` Capturing group
`(?:...)` Non-capturing group
`(?<name>...)` Named capturing group
`\1`, `\k<name>` Backreference to group 1 / named group
`(?=...)` Positive lookahead
`(?!...)` Negative lookahead
`(?<=...)` Positive lookbehind
`(?<!...)` Negative lookbehind
`i` Case-insensitive
`g` Global (JS: find all matches, keeps `lastIndex` state)
`m` Multiline (`^`/`$` match at line breaks)
`s` Dot matches newline too (JS/PCRE `DOTALL`)
`u` Unicode mode (JS: required for `\p{...}`, surrogate-pair-safe)
`y` Sticky — match only at `lastIndex`, no scanning ahead (JS only)

Common patterns

Extract capture groups by name (JS)

const m = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/.exec('2026-09-29');
m.groups.year;  // "2026"

Loop over every match without an infinite loop

const re = /\d+/g;
let m;
while ((m = re.exec('a1 b22 c333')) !== null) {
  console.log(m[0], m.index);
}
// Forgetting the `g` flag here means re.exec() always returns the
// first match and re.lastIndex never advances -- infinite loop.

Replace with a backreference

'2026-09-29'.replace(/(\d{4})-(\d{2})-(\d{2})/, '$2/$3/$1');
// -> "09/29/2026"

Validate with anchors, not `.test()` alone

/^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i.test('user@example.com'); // true

This is a loose email check for form UX, not RFC 5322 validation — never reject a real address just because it doesn't match a regex.

Lookahead for password rules

// At least 8 chars, one digit, one uppercase — order-independent
/^(?=.*[A-Z])(?=.*\d).{8,}$/.test('Passw0rd'); // true

Pitfalls

  • . doesn't match newlines by default: a pattern like /start.end/ silently fails across multi-line input. Add the s (dotAll) flag, or use [\s\S] which matches everything including \n in every engine.
  • Greedy quantifiers over-match: /<.>/ against <a><b> grabs the whole string, not just <a>. Use the lazy form /<.?>/ or a negated class /<[^>]*>/.
  • *^/$ mean start/end of string, not line, unless you add m:* without the multiline flag, ^ only matches position 0 even in a string with embedded \n.
  • JS g-flagged regexes are stateful: a global regex remembers lastIndex between calls to .exec()/.test() on the same object. Reusing one across unrelated inputs produces skipped or missed matches — create a fresh regex or reset lastIndex = 0.
  • PCRE features JS doesn't have: possessive quantifiers (+, ++), atomic groups ((?>...)), and recursion ((?R)) are valid in PHP's preg_ (PCRE) but throw a SyntaxError in JavaScript, in every mode.
  • \K (PCRE's "reset match start") is worse than a SyntaxError in plain JS regexes — it's silently wrong: without the u/v flag, JS treats \K as an identity escape for a literal K, so /foo\Kbar/.test('fooKbar') is true and .test('foobar') is false — no error, just a pattern that quietly means something else. It only throws (SyntaxError: Invalid escape) once you add the u or v flag, which rejects unrecognized letter escapes. Conversely, JS's \p{Emoji} and other Unicode property escapes need the u flag; PCRE needs /u too but supports a broader property set out of the box.

Related ZipKit tools

  • Regex Tester — test a pattern against real input with live highlighting and capture-group inspection before shipping it.
  • Reverse Regex Generator — go the other direction: generate a sample string that matches a given pattern, useful for building test fixtures.

Related cheatsheets