Regex Cheat Sheet With Copy-Paste Patterns (And Why Yours Is Slow)
β‘ Quick Answer
A practical regex cheat sheet β character classes, quantifiers, anchors, groups, lookarounds, flags, 15 ready patterns, and why catastrophic backtracking kills servers.
Get more content like this on Telegram!
Daily AI tips, notes & resources β free
Advertisement
Regex Cheat Sheet With Copy-Paste Patterns
A regular expression is a small program for describing the shape of text. Most developers learn ten symbols, copy the rest, and never find out why their pattern occasionally hangs the server.
This sheet gives you the syntax tables, fifteen patterns you can paste today, and the two performance traps that turn a working expression into an outage.
Updated for 2026. Covers JavaScript (ES2024), Python 3 re, and PCRE2.
Character Classes
| Pattern | Matches |
|---|---|
. | Any character except newline |
\d | Digit 0-9 |
\D | Any non-digit |
\w | Word character: letter, digit, underscore |
\W | Any non-word character |
\s | Whitespace: space, tab, newline |
\S | Any non-whitespace |
[abc] | One of a, b, c |
[^abc] | Anything except a, b, c |
[a-z] | Range: lowercase letters |
[a-zA-Z0-9_] | Equivalent to \w |
What people get wrong: treating \w as "letters". It includes digits and the underscore. A username validator built on \w silently accepts ___.
Inside a character class most metacharacters lose their special meaning. [.+*] matches a literal dot, plus, or asterisk β no escaping required. The exceptions are ^ (only special in first position), - (put it first or last to keep it literal), and ].
Quantifiers
| Pattern | Meaning |
|---|---|
* | 0 or more |
+ | 1 or more |
? | 0 or 1 (optional) |
{3} | Exactly 3 |
{3,} | 3 or more |
{3,5} | Between 3 and 5 |
*? +? ?? {n,m}? | Lazy versions of the above |
Greedy vs lazy
const html = '<b>bold</b> and <i>italic</i>';
html.match(/<.+>/)[0]; // "<b>bold</b> and <i>italic</i>"
html.match(/<.+?>/)[0]; // "<b>"The first pattern is greedy: .+ consumes the entire line, then backs up character by character until the final > can match β so it stops at the last > in the string. The lazy version .+? takes the minimum and stops at the first >.
The rule: any time . plus a quantifier is followed by a literal delimiter, you almost certainly want the lazy form. Better still, replace . with a negated class β <[^>]+> β which cannot overshoot in the first place and runs faster because there is nothing to backtrack.
Anchors and Boundaries
| Pattern | Matches |
|---|---|
^ | Start of string (start of line with m flag) |
$ | End of string (end of line with m flag) |
\b | Word boundary |
\B | Not a word boundary |
\A | Absolute start of string (Python, PCRE β not JS) |
\z | Absolute end of string (Python, PCRE β not JS) |
/cat/.test('concatenate'); // true β substring match
/\bcat\b/.test('concatenate'); // false β needs a whole word
/^\d+$/.test('42\nabc'); // false β anchors span the whole string\b is a zero-width assertion: it matches the position between a word character and a non-word character, consuming nothing.
What people get wrong: validating with an unanchored pattern. /\d{4}/ on "abc1234def" returns true. A validator without ^ and $ is a search, not a validation.
Groups and Capture
| Pattern | Purpose |
|---|---|
(abc) | Capturing group β grouped and stored |
(?:abc) | Non-capturing group β grouped only |
(?<name>abc) | Named group (JS, PCRE) |
(?P<name>abc) | Named group (Python) |
\1 | Backreference to group 1 |
\k<name> | Named backreference (JS, PCRE) |
a|b | Alternation β a or b |
const re = /(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/;
const { y, m, d } = '2026-07-23'.match(re).groups;
// y = "2026", m = "07", d = "23"This splits an ISO date into three named pieces you can destructure directly. Named groups survive refactoring; numbered groups do not β adding one pair of parentheses anywhere earlier renumbers everything after it.
Use (?:...) by default. Reach for a capturing group only when you actually need the value.
Lookahead and Lookbehind
Zero-width assertions. They test what surrounds a position without consuming it.
| Pattern | Name | Meaning |
|---|---|---|
(?=abc) | Positive lookahead | Followed by abc |
(?!abc) | Negative lookahead | Not followed by abc |
(?<=abc) | Positive lookbehind | Preceded by abc |
(?<!abc) | Negative lookbehind | Not preceded by abc |
// price without capturing the currency symbol
'$49.99'.match(/(?<=\$)\d+\.\d{2}/)[0]; // "49.99"
// password: 8+ chars, one digit, one lowercase, one uppercase
/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$/The password pattern stacks three independent lookaheads at the string start. Each one scans forward for its requirement and then resets to position zero, so all three conditions apply to the same string without dictating any ordering. .{8,} then does the actual consuming.
Flavour warning: JavaScript has supported lookbehind since ES2018 and allows variable width. Python's re module requires fixed-width lookbehind β (?<=ab|cde) is an error. Check before you copy.
Flags
| Flag | Name | Effect |
|---|---|---|
i | Ignore case | A matches a |
g | Global (JS) | Find all matches, not just the first |
m | Multiline | ^ and $ match at each line |
s | Dotall | . also matches newline |
u | Unicode (JS) | Correct handling of astral characters |
x | Verbose (Python, PCRE) | Ignore whitespace, allow # comments |
import re
pattern = re.compile(r"""
(\d{3}) # area code
[-.\s]? # optional separator
(\d{4}) # local number
""", re.VERBOSE)The x / VERBOSE flag lets a pattern be written across multiple lines with comments. JavaScript has no verbose mode β build long patterns from string concatenation or RegExp source composition instead.
What people get wrong: reusing a g-flagged RegExp object in JavaScript. It carries a mutable lastIndex, so consecutive .test() calls on the same object alternate true and false. Either create the regex fresh or drop g when testing.
15 Ready Patterns
// 1. Email (pragmatic, not RFC 5322)
/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/
// 2. URL (http/https)
/^https?:\/\/[^\s/$.?#].[^\s]*$/i
// 3. IPv4
/^(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)){3}$/
// 4. ISO date YYYY-MM-DD
/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/
// 5. 24-hour time HH:MM
/^([01]\d|2[0-3]):[0-5]\d$/
// 6. Hex colour, 3 or 6 digits
/^#?([0-9a-f]{3}|[0-9a-f]{6})$/i
// 7. US phone, loose
/^\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$/
// 8. Slug
/^[a-z0-9]+(?:-[a-z0-9]+)*$/
// 9. Strong password: 8+, upper, lower, digit, symbol
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\w\s]).{8,}$/
// 10. Trim whitespace (replace with "")
/^\s+|\s+$/g
// 11. Collapse repeated whitespace (replace with " ")
/\s{2,}/g
// 12. Duplicate consecutive words
/\b(\w+)\s+\1\b/gi
// 13. UUID v4
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
// 14. Leading/trailing slashes on a path
/^\/+|\/+$/g
// 15. Semver core (major.minor.patch)
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/Pattern 3 is the one worth reading closely: each octet is an alternation of the four legal numeric shapes, which is why it rejects 999.1.1.1 where a naive \d{1,3} would not. Pattern 12 uses a backreference β \1 matches whatever group 1 captured β to find the the in prose.
On email: stop hunting for a perfect pattern. The full RFC 5322 grammar is thousands of characters long and still accepts addresses no mail server will deliver to. Validate loosely, then send a confirmation email. That is the only validation that proves anything.
Catastrophic Backtracking
This is the section that matters in production.
// DANGEROUS
/^(\w+\s?)+$/.test('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!');That takes seconds to minutes and pins a CPU core. The string does not match β and proving it does not match is the expensive part.
The cause is nested quantifiers over overlapping character sets. \w+ can match aaaa as one chunk, or aaa + a, or aa + aa, and the outer + allows every one of those splits. For n characters there are roughly 2βΏ ways to divide them. On a match the engine finds one early and stops; on a failure it must try all of them.
Thirty characters is about a billion attempts. This is ReDoS β regular expression denial of service β and it is a real CVE class, not a theoretical concern.
How to avoid it:
| Do | Instead of |
|---|---|
^\w+(?:\s\w+)*$ | ^(\w+\s?)+$ |
<[^>]+> | <.+?> |
| Anchor both ends | Leave the pattern floating |
| Cap input length before matching | Trust user input |
The safe rewrite works because each character has exactly one way to be consumed β there are no alternative splits to explore.
PCRE and Python 3.11+ offer possessive quantifiers (\w++) and atomic groups ((?>...)), which forbid backtracking into a section entirely. JavaScript has neither, so in JS the only defences are pattern discipline and input length limits.
Flavour Differences
| Feature | JavaScript | Python re | PCRE2 |
|---|---|---|---|
| Named group syntax | (?<n>) | (?P<n>) | both |
| Lookbehind | Variable width | Fixed width only | Variable width |
| Verbose / commented mode | No | re.VERBOSE | /x |
Atomic group (?>...) | No | 3.11+ | Yes |
Possessive ++ | No | 3.11+ | Yes |
Recursion (?R) | No | No | Yes |
\d matches Unicode digits | ASCII only | Yes by default | Configurable |
Python's \d matching non-ASCII digits by default surprises people: re.match(r'\d', 'Ω€') succeeds. Pass re.ASCII if you mean 0-9 only.
When NOT to Use Regex
HTML. It is recursively nested; a regular language cannot count nesting depth. Any pattern that appears to work will break on a nested tag, an attribute containing >, a comment, or a <script> block. Use a DOM parser.
JSON. Same argument, plus escaped quotes inside strings. Every language ships a JSON parser. Use it.
CSV. Quoted fields can contain commas and embedded newlines. Use a CSV library.
Arithmetic ranges. "A number between 1 and 65535" as a regex is an unreadable alternation. Parse to an integer and compare.
The honest test: if the format you are matching can nest inside itself, regex is the wrong tool. See the Python cheat sheet for the parsing libraries that replace it, and the Linux commands cheat sheet for grep -E and sed usage where regex genuinely is the right answer.
The Five Mistakes
1. Unanchored validators. Without ^ and $ you have written a search. /\d{4}/ says yes to abc1234def.
2. Nested quantifiers. (\w+)+ and friends are exponential on failure. Rewrite as \w+(?:\s\w+)*.
3. Greedy .* before a delimiter. Use a negated character class, not just a lazy quantifier β it is both correct and faster.
4. Reusing a g-flagged regex in JavaScript. lastIndex persists between calls, so .test() alternates true and false on identical input.
5. Parsing structured formats. HTML, JSON, CSV, XML. Reach for the parser your language already ships.
Print This Section
CLASSES \d digit \w letter/digit/_ \s whitespace
[^abc] negated . any char except newline
QUANT * 0+ + 1+ ? 0 or 1 {3,5} range
add ? for LAZY: .*? .+?
ANCHOR ^ start $ end \b word boundary
VALIDATION MUST BE ^...$ ANCHORED
GROUPS (x) capture (?:x) group only (?<n>x) named
\1 backreference
LOOK (?=x) ahead (?!x) not ahead
(?<=x) behind (?<!x) not behind
FLAGS i case g all m per-line ^$ s dot matches \n
DANGER (\w+)+ exponential β ReDoS
<.+> greedy overshoot β use <[^>]+>
NEVER HTML Β· JSON Β· CSV Β· XML β use a parserA regex that works on your ten test strings is not finished. Anchor it, replace every . you can with an explicit class, and check whether any quantifier sits inside another one.
π Next in this collection: Bash Scripting Cheat Sheet, or return to The Complete Developer Cheat Sheet Collection.
Advertisement
π¬ DiscussionPowered by GitHub Discussions
Frequently Asked Questions

AI & Software Engineering Editorial Team
The AiTechWorlds editorial team writes and reviews in-depth guides on artificial intelligence, machine learning, prompt engineering, programming, and developer tools. Every article is fact-checked against primary sources and kept up to date for working developers and CS students.
Not sure yet? Ask AI about this article
Get an instant, unbiased AI summary of βRegex Cheat Sheet With Copy-Paste Patterns (And Why Yours Is Slow)β.
Advertisement
Related Articles
Bash Scripting Cheat Sheet (The First Line Every Script Needs)
A practical Bash scripting cheat sheet β variables, conditionals, loops, functions, and the set -euo pipefail line that turns silent failure into loud failure.
15 Coding Interview Patterns That Solve Most Problems
The 15 coding interview patterns that cover most problems β the signal that identifies each one, a minimal code skeleton, and a two-minute recognition table.
CSS and Tailwind Cheat Sheet: Flexbox, Grid and Centering Solved
A practical CSS and Tailwind cheat sheet β Flexbox vs Grid decision rules, every centering method, responsive breakpoints, and the specificity traps.
Data Structures and Big-O Cheat Sheet for Coding Interviews
A practical big O cheat sheet β the complexity ladder with real examples, data structure operation tables, and how to state your complexity in an interview.