Regex Cheatsheet
Regex syntax explained symbol by symbol, with real examples and ready-to-copy patterns.
Anchors — position in the text
Symbols that don't match a character, but a position — start/end of string or line, word boundary.^
Start of string/line
Marks a position, not a character — without the m flag, the start of the whole string; with m, the start of each line.
$
End of string/line
The counterpart to ^ — without the m flag, the end of the whole string; with m, the end of each line.
\b
Word boundary
A position between a word character (\w) and one that isn't — it consumes no character, only marks the transition.
\B
Non-word boundary
The opposite of \b — matches any position that is not a word boundary (both sides alike: both word characters, or both non-word).
Character Classes — what kind of character
Symbols that match a single character from a set — digit, letter, whitespace, or a hand-defined set.\d
Digit
Equivalent to [0-9] — matches any digit from 0 to 9.
\w
Word character
Letters, digits, and underscore — equivalent to [A-Za-z0-9_].
\s
Whitespace
Space, tab, line break, and other whitespace characters.
.
Any character
Matches any single character, except a line break — unless the s flag is active.
[...]
Character class
Matches any one of the characters listed inside the brackets — accepts ranges, like [a-z].
[^...]
Negated class
The ^ right after the bracket negates the class — matches any character that is NOT in the list.
Quantifiers — how many times
Control how many times the preceding element can repeat — from zero to unlimited.*
Zero or more
The preceding element may appear zero, one, or many times in a row.
+
One or more
Like *, but requires at least one occurrence of the preceding element.
?
Zero or one (optional)
Marks the preceding element as optional — present or absent, both match.
{n,m}
Repetition range
Between n and m occurrences of the preceding element — {n} is exact, {n,} is "at least n", {,m} is "at most m".
*? +?
Lazy quantifier
By default, *, +, and {n,m} are greedy (they match as much as possible) — an extra ? right after makes the quantifier lazy, matching as little as possible.
Groups & Alternation — grouping and choosing
Group part of the pattern to apply a quantifier, capture the matched text, or choose between alternatives.(...)
Capturing group
Groups part of the pattern and stores the matched text for later use (backreference, replacement).
(?:...)
Non-capturing group
Groups like (...), but without generating a numbered capture — useful when only the grouping matters, not the value.
|
Alternation (OR)
Matches one alternative or the other — tries the left one first.
(?<name>...)
Named group
Like (...), but the capture gets a name (accessible as match.groups.name) instead of just a positional number.
Lookaround — checking without consuming
Check what comes before/after a position without including that text in the final match.(?=...)
Positive lookahead
Matches a position followed by the given pattern, without consuming that text in the result.
(?!...)
Negative lookahead
Matches a position NOT followed by the given pattern.
(?<=...)
Positive lookbehind
Matches a position preceded by the given pattern, without consuming that text in the result.
(?<!...)
Negative lookbehind
Matches a position NOT preceded by the given pattern.
Flags — how the engine processes the pattern
Modifiers that change the behavior of the whole expression — case sensitivity, all occurrences, multiple lines.i
i — case-insensitive
Ignores the difference between uppercase and lowercase across the whole pattern.
g
g — global
Finds every occurrence in the text, not just the first one.
m
m — multiline
Makes ^ and $ match the start/end of each line, not just of the whole string.
s
s — dotall
Makes . also match a line break, which it ignores by default.
u
u — unicode
Treats the pattern as a sequence of Unicode code points, not UTF-16 units — required to correctly match characters outside the BMP (like most emoji) and to use \p{...}.
Ready-made pattern library
Tested, ready-to-copy regex — each one with an honest caveat when a relevant limitation exists.
/^[^\s@]+@[^\s@]+\.[^\s@]+$/
Basic email address shape: something@something.something, no spaces.
URL
/^https?:\/\/[^\s/$.?#][^\s]*$/
An http/https URL with an optional path, query string, and fragment.
IPv4
/^(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/
A valid IPv4 address — four octets from 0 to 255, separated by dots.
IPv6
/^([\da-fA-F]{1,4}:){7}[\da-fA-F]{1,4}$/
An IPv6 address in its full form — eight groups of up to 4 hex digits, separated by colons.
Phone number (BR)
/^(?:\+55\s?)?\(?\d{2}\)?[\s-]?\d{4,5}-?\d{4}$/
A Brazilian phone number with area code, with or without +55, parentheses, and a hyphen.
CEP (postal code)
/^\d{5}-?\d{3}$/
Brazilian postal code (CEP) — 8 digits, with an optional hyphen between the fifth and sixth.
Hex color
/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/
A CSS hex color — 3, 6, or 8 digits (the last case includes the alpha channel).
Date (ISO 8601)
/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/
A date in YYYY-MM-DD format, with month between 01-12 and day between 01-31.
This reference covers JavaScript
The syntax and behavior here are JavaScript/ECMAScript's own regex engine — what runs natively in any browser, with no library at all. Most of the syntax is nearly identical across dialects (PHP/Perl's PCRE, Python's re, .NET's regex), but a few points diverge in real ways: lookbehind — (?<=...) and (?<!...) — only reached PCRE in recent versions, and Python's re only in 3.11; named groups use (?<name>...) in JavaScript/PCRE/.NET, but (?P<name>...) in Python; POSIX classes like [:alpha:] exist in PCRE/POSIX but not in JavaScript, which uses \w/\d/\s instead. When porting a regex from another context to JavaScript (or vice versa), it's worth checking these points first.
How a regex engine actually searches
Behind every greedy quantifier, the engine tries to consume as much as possible and only backs off (backtracks) when the rest of the pattern can't match. That backing off has a cost: a poorly designed pattern with nested, ambiguous quantifiers over the same stretch of text (e.g. (a+)+b against a long string with no "b" at the end) can make the engine try an exponential number of combinations before giving up — the phenomenon known as "catastrophic backtracking", capable of freezing a page or an API for seconds or minutes with a relatively short input. Lazy quantifiers (see Quantifiers, above) don't eliminate the risk on their own, but avoiding nested quantifiers over the same character set is the most effective defense.
Capture groups in practice: .replace()
A capture group's practical value shows up in replacement: 'JavaScript'.replace(/(\w+)Script/, '$1.js') uses $1 to refer to whatever the first group captured. Named groups make this more readable in patterns with several groups: with (?<first>\w+)\s(?<last>\w+), a match's result carries match.groups.first and match.groups.last instead of match[1]/match[2] — the name survives any future reordering of the pattern, the positional number doesn't. Non-capturing groups (?:...) exist precisely to group without competing for a capture number when that capture will never be used.
Frequently asked questions
Because each regex engine evolved from a different tradition (Perl's PCRE, Python's re, JavaScript's native engine, .NET's regex) and converged on a very similar syntax core, but with edge-case details that diverged over decades — lookbehind, named groups, and POSIX classes are the most common sources of friction when porting a regex from one context to another (see "This reference covers JavaScript", above).
Only the format (11 or 14 digits, with or without punctuation) — not the check digit, which requires an arithmetic calculation over the preceding digits, something a regex alone can't express. To actually validate one, you need to run the check-digit algorithm (see Nexinon's CPF/CNPJ Generator/Validator).
Because RFC 5322 (the actual email address spec) allows formats that almost no real email provider accepts in practice — quoted addresses, comments inside the address, and other extremely rare edge cases. The regex in the pattern library above covers the shape that 99% of real emails follow, enough to validate a form field; the only way to know an email truly exists is to send a confirmation message.
The classic example is trying to extract an HTML tag: against '<a><b>', the greedy pattern <.+> matches the whole string '<a><b>' (consumes as much as possible, including the '>' in the middle), while the lazy <.+?> matches just '<a>' (stops as soon as the first valid alternative appears). Someone expecting to extract one tag at a time and using the greedy quantifier by mistake ends up with silently wrong results — the bug throws no error, it just returns more text than it should.
For clarity, and in large patterns with many groups, to avoid losing track of which capture number corresponds to which group — every (?:...) is one fewer captured group to mentally renumber when editing the pattern later. The performance impact is minimal in most cases; the real benefit is avoiding human confusion, not execution speed.
Technically yes, but with a real caveat: if that regex will process untrusted input (text coming from a user, for instance), a poorly designed pattern with nested quantifiers can suffer "catastrophic backtracking" (see "How a regex engine actually searches", above) and freeze your server with a relatively short, malicious input — a denial-of-service vector known as ReDoS. Testing the regex against deliberately adversarial input (long, almost-but-not-quite-valid strings) before using it in production is the simplest defense.
Nexinon Principles
Privacy
Your data never leaves your browser.No account needed
Use it now, no account or password.Free
No usage limits, no paid plan.Trustworthy content
Full explanation behind every tool, not just the result.