Regex Cheat Sheet: Syntax Tables and Ready-Made Patterns

Regex syntax in tables, plus patterns tested before publishing.

No signup, no tracking

A regular expression is a small pattern language for describing text. The syntax is dense by design — every character earns its place — which makes it fast to write and genuinely hard to remember between uses.

This is the lookup version: seven tables covering the syntax you actually reach for, followed by a set of ready-made patterns. Every pattern on this page was executed against passing and failing inputs before publication, and the syntax descriptions follow MDN’s Regular expressions reference.

Metacharacters

TokenMeaning
.Any character except a line terminator
\Escapes the next character, making it literal
|Alternation — matches the left side or the right side
[ ]Character class — matches one character from the set
[^ ]Negated class — matches one character not in the set
( )Capturing group
{ }Explicit repetition count

These are the characters that do not stand for themselves. To match one literally, put a backslash in front of it: \. matches an actual full stop, while an unescaped . matches any character. That is the single most common mistake in patterns written for domain names and filenames, where an unescaped dot quietly matches far more than intended.

Quantifiers

TokenMeaningExample
*Zero or morea*
+One or morea+
?Zero or one (optional)a?
{n}Exactly n times\d{4}
{n,}n or more times\d{2,}
{n,m}Between n and m times\d{2,4}
*? +? ?? {n,m}?Lazy: match as few as possible<.+?>

Quantifiers are greedy by default: they take as much as possible and then give characters back until the rest of the pattern fits. Adding ? makes them lazy. Against the input <a><b>, the pattern <.+> matches the whole string while <.+?> matches only <a>. This single distinction is behind most "why did my regex eat the whole line" questions.

Character classes

TokenMatches
\dA digit, 0 to 9
\DAnything that is not a digit
\wWord character: A-Z, a-z, 0-9 and underscore
\WAnything that is not a word character
\sWhitespace: space, tab, newline, carriage return
\SAnything that is not whitespace
[a-z]Range — any lowercase letter
[^0-9]Any character except a digit
\p{L}Any Unicode letter — requires the u flag
\P{L}Any character that is not a Unicode letter

In JavaScript \w and \d are ASCII-only, so ^\w+$ rejects any word containing an accent or a non-Latin letter. For text in languages other than English, use \p{L} with the u flag instead. Python behaves the opposite way: \w and \d already include Unicode in str patterns unless you pass re.ASCII.

Anchors and boundaries

TokenAsserts
^Start of the input, or start of a line with the m flag
$End of the input, or end of a line with the m flag
\bWord boundary — the edge between \w and \W
\BNot a word boundary

Anchors match a position, not a character, so they consume nothing. \bcat\b finds the word cat in "cat concat" exactly once, because the cat inside concat has a word character to its left.

Groups, alternation and backreferences

TokenMeaning
( ... )Capturing group, referenced by number
(?: ... )Non-capturing group — groups without capturing
(?<name> ... )Named capturing group
\1, \2Backreference to capture group 1, 2 ...
\k<name>Backreference to a named group
/(?<year>\d{4})-(?<month>\d{2})/    named groups: .groups.year gives "2026"
/(?:ab)+(c)/                       group 1 is "c" — (?: ...) does not capture
/\b(\w+)\s+\1\b/                   finds repeated words: "the the cat"
Capturing, grouping without capturing, and referring back to a capture

Use non-capturing groups whenever you only need the grouping. Capture numbering is positional, so inserting one ordinary group near the start of a pattern silently renumbers every group after it and breaks whatever code reads match[3]. Named groups avoid that problem entirely.

Lookaround

TokenMeaning
(?= ... )Positive lookahead — followed by
(?! ... )Negative lookahead — not followed by
(?<= ... )Positive lookbehind — preceded by
(?<! ... )Negative lookbehind — not preceded by
/\d+(?= USD)/     matches 45 in "45 USD" but not in "45 EUR"
/(?<=\$)\d+/      matches 99 in "$99", excluding the dollar sign
/^(?=.*\d)(?=.*[a-z]).{8,}$/   at least one digit and one letter, 8+ characters
Lookaround tests a condition without consuming characters

Flags

FlagEffect
gGlobal — find all matches, not just the first
iCase-insensitive
mMultiline — ^ and $ match line boundaries
sDot-all — . also matches newlines
uUnicode mode — enables \p{...} and code-point handling
ySticky — match only from lastIndex

The m flag is narrower than its name suggests: it changes only what ^ and $ mean, and has no effect on the dot. To make . cross line breaks you need s. The two are independent and frequently both required when matching across multi-line input.

Ready-made patterns

MatchesPattern
Email (pragmatic)^[^\s@]+@[^\s@]+\.[^\s@]{2,}$
IPv4 address^((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$
ISO 8601 date^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
ISO 8601 date and time^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})?$
24-hour time^([01]\d|2[0-3]):[0-5]\d(:[0-5]\d)?$
HTTP or HTTPS URL^https?://[^\s/$.?#][^\s]*$
Hex color^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$
URL slug^[a-z0-9]+(?:-[a-z0-9]+)*$
UUID, versions 1 to 5^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
Integer^-?\d+$
Decimal number^-?\d+(\.\d+)?$
Duplicated word\b(\w+)\s+\1\b
HTML tag</?[a-zA-Z][^>]*>
Trailing whitespace (with m)[ \t]+$

A word about the email pattern: it is deliberately loose, and that is the honest choice. RFC 5322 permits quoted local parts, comments and nested constructs that no readable regex captures, while the addresses people actually mistype are rejected by no regex at all. The WHATWG HTML standard sidesteps this by defining its own intentionally narrower pattern for input type="email" — which, notably, accepts a@b with no dot in the domain. Use a regex to catch typos, then confirm the address by sending mail to it. That is the only real validation.

Test these patterns

A table cannot tell you why a pattern fails on your particular input. The Regex Tester on this site highlights matches live as you type, lists each capture group with its contents, and lets you toggle flags to see the effect immediately — which is the fastest way to understand greedy versus lazy matching. It runs entirely in your browser, so patterns and test text never leave your device.

Related tools