Regex Cheatsheet for 2026
Quick reference for regex patterns, flags, and tested examples.
Regex syntax is dense enough that even people who use it weekly forget the details. This cheatsheet covers the constructs you reach for daily, plus the 2026-era additions — Unicode property escapes and the v flag — and the performance trap that takes production services down.
Character Classes
\d/\D— digit / non-digit\w/\W— word character (letters, digits, underscore) / everything else\s/\S— whitespace / non-whitespace.— any character except newline (add thesflag to include newlines)[abc],[a-z],[^abc]— set, range, negated set\p{L},\p{Script=Hangul}— Unicode property escapes (require theuorvflag);\wis ASCII-only, so use\p{L}when matching international text
Quantifiers
?— zero or one+— one or more{n},{n,},{n,m}— exact, at-least, bounded countsa*— zero or more of a- Greedy by default: quantifiers take the longest match that still allows the rest of the pattern to succeed
- Append
?for the lazy version —+?takes the shortest match; the classic use is<.+?>to match one tag instead of an entire line of tags
Anchors and Boundaries
^and$— start and end of string; with themflag, of each line\b/\B— word boundary / non-boundary;\bcat\bmatches "cat" but not "category"- Boundary definitions follow
\w, so they are also ASCII-only by default
Groups and Backreferences
(abc)— capturing group, numbered left to right(?:abc)— non-capturing; use for pure grouping to keep numbering stable and save allocations(?<name>abc)— named capture, read viamatch.groups.name\1and\k<name>— backreferences;(["'])(.?)\1matches a string quoted by either quote type
Lookarounds
(?=x)/(?!x)— positive / negative lookahead(?<=x)/(?<!x)— positive / negative lookbehind (JavaScript since ES2018)- Lookarounds consume no characters, which makes them ideal for password rules and insert-position matching, e.g. thousands separators:
/\B(?=(\d{3})+(?!\d))/g
Flags
g— all matches, not just the first; stateful withexec, a classic source of alternating-match bugsi— case-insensitivem—^and$match at line breakss— dot matches newlineu— proper Unicode: astral characters are one unit, property escapes enabledv(ES2024) — everythingudoes, plus set operations like[\p{L}--[aeiou]](letters except vowels) and string properties like\p{RGI_Emoji}y— sticky, match exactly atlastIndex; the building block for hand-written lexers
Battle-Tested Patterns
Email (pragmatic): ^[\w.+-]+@[\w-]+\.[\w.-]+$
IPv4 octet-exact: ^(?:(?:25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|1?\d?\d)$
ISO 8601 date: ^\d{4}-\d{2}-\d{2}$
UUID v4: ^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
URL slug: ^[a-z0-9]+(?:-[a-z0-9]+)*$
Hex color: ^#(?:[0-9a-fA-F]{3}){1,2}$
The email pattern is deliberately loose. A fully RFC 5321-correct pattern is enormous and still cannot tell you whether the mailbox exists — validate format loosely, then confirm by sending mail.
Catastrophic Backtracking
The one regex behavior that causes outages. Nested quantifiers over overlapping alternatives — shapes like (a+)+b or (\w|\d)+$ — force the backtracking engine to try exponentially many partitions when a long input almost matches but fails at the end. A 40-character malicious string can pin a CPU core for minutes; this is ReDoS.
Defenses:
- Make alternatives non-overlapping and avoid quantifying an already-quantified group
- Prefer explicit character classes over
. - Linear-time engines (RE2, Rust's regex crate) are immune by construction — the trade-off is no backreferences or lookarounds
- Never run user-supplied patterns against user-supplied input on a request thread; if you must, apply a timeout in a worker
Habits That Pay Off
- Compile once, reuse: a regex literal inside a hot loop re-creates state in some engines
- Anchor patterns whenever position is known —
^fails non-matches immediately instead of scanning - Comment complex patterns by composing them from named source strings
- Test with adversarial inputs: empty string, very long near-matches, Unicode beyond ASCII
Engines Differ More Than Syntax
The same pattern can behave differently across engines, and knowing which family you are on prevents subtle porting bugs:
- Backtracking engines — JavaScript (V8's Irregexp), PCRE2, Python's re, Java's java.util.regex. Full feature set, exponential worst case.
- Linear-time engines — RE2 (used by Go's regexp), Rust's regex crate. Guaranteed O(n) matching via automata; no backreferences, no lookaround.
- Hybrids — .NET offers a NonBacktracking mode; PCRE2 ships a DFA matching function.
Feature gaps to check before copying a pattern from Stack Overflow: lookbehind (unsupported in Safari before 16.4, absent in Go/RE2), possessive quantifiers and atomic groups (PCRE and Java only — JavaScript emulates them with lookahead-plus-backreference tricks), and \p property escape coverage. In JavaScript specifically, prefer matchAll for iterating global matches — it sidesteps the shared lastIndex state that makes exec loops fragile — and remember that String.replace with a plain string replaces only the first occurrence; you need a regex with the g flag.
Iterate on patterns live with match highlighting in the Regex Tester at sdk.is/regex-tester.