A regular expression (regex) is a compact pattern language for finding, validating and transforming text. It’s built into nearly every programming language, text editor and command-line tool. Regex has a reputation for being unreadable, but you need only a dozen constructs for most everyday jobs. This cheat sheet covers them with examples. Try every pattern live in our regex tester, which highlights matches and groups as you type.
Literal characters and special characters
Most characters match themselves: cat matches “cat” in “concatenate”. These metacharacters have special meaning and must be escaped with a backslash to match literally:
. ^ $ * + ? ( ) [ ] { } | \ /
To match a full stop, write \.; to match a literal $, write \$. (The / only needs escaping inside JavaScript regex literals.)
Character classes
| Pattern | Matches |
|---|---|
. |
Any character except a newline |
\d |
A digit (0–9) |
\w |
A word character: letter, digit or underscore |
\s |
Whitespace: space, tab, newline |
\D, \W, \S |
The opposite of the above |
[abc] |
One of a, b or c |
[a-z] |
Any lowercase letter a–z |
[^0-9] |
Any character that is not a digit |
[A-Za-z0-9_-] |
Letters, digits, underscore or hyphen |
Inside square brackets most metacharacters lose their meaning; - defines a range unless it is first or last.
Quantifiers
| Pattern | Meaning |
|---|---|
* |
0 or more |
+ |
1 or more |
? |
0 or 1 (optional) |
{3} |
Exactly 3 |
{2,5} |
Between 2 and 5 |
{2,} |
2 or more |
Example: colou?r matches both “color” and “colour”. \d{4} matches four digits.
Anchors and boundaries
| Pattern | Meaning |
|---|---|
^ |
Start of string (or line with m flag) |
$ |
End of string (or line with m flag) |
\b |
Word boundary |
\B |
Not a word boundary |
^\d+$ matches a string made only of digits. \bcat\b matches “cat” but not “concatenate”.
Groups, alternation and backreferences
| Pattern | Meaning |
|---|---|
(abc) |
Capturing group |
(?:abc) |
Non-capturing group |
(?<year>\d{4}) |
Named group |
a|b |
a or b |
\1 |
Backreference to group 1 |
Example: ^(Mr|Mrs|Ms|Dr)\.? [A-Z][a-z]+$ matches “Dr Smith” and “Mrs. Jones”. (\w+) \1 finds doubled words like “the the”.
In replacements, groups are usually referenced as $1 (JavaScript, .NET) or \1 (Python, sed). Reformatting a UK-style date 08/10/2026 to ISO: find (\d{2})/(\d{2})/(\d{4}), replace with $3-$2-$1 → 2026-10-08.
Lookarounds
| Pattern | Meaning |
|---|---|
X(?=Y) |
X followed by Y |
X(?!Y) |
X not followed by Y |
(?<=Y)X |
X preceded by Y |
(?<!Y)X |
X not preceded by Y |
Example: (?<=£)\d+(\.\d{2})? extracts the number from “£49.99” without the pound sign. Password rule “at least one digit”: ^(?=.*\d).{8,}$.
Flags
| Flag | Effect |
|---|---|
i |
Case-insensitive |
g |
Global: find all matches (JavaScript) |
m |
Multiline: ^ and $ match at each line |
s |
Dotall: . also matches newlines |
u |
Unicode mode (JavaScript) |
x |
Extended: ignore whitespace and allow comments (PCRE, Python re.X) |
Greedy vs lazy
Quantifiers are greedy by default: they match as much as possible. Add ? to make them lazy.
Text: <b>bold</b> and <b>more</b>
<b>.*</b>matches the entire string, from the first<b>to the last</b>.<b>.*?</b>matches<b>bold</b>, then<b>more</b>separately.
Often a negated class is clearer and faster: <b>[^<]*</b>.
Practical patterns
| Task | Pattern | Notes |
|---|---|---|
| Simple email check | ^[^\s@]+@[^\s@]+\.[^\s@]+$ |
Good enough for forms; verify by sending email |
| ISO date | ^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$ |
Doesn’t check days per month |
| UK date dd/mm/yyyy | ^(0[1-9]|[12]\d|3[01])/(0[1-9]|1[0-2])/\d{4}$ |
|
| 24-hour time | ^([01]\d|2[0-3]):[0-5]\d$ |
00:00 to 23:59 |
| UK postcode (simplified) | ^[A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2}$ |
Use with i flag |
| US ZIP code | ^\d{5}(-\d{4})?$ |
12345 or 12345-6789 |
| International phone (E.164) | ^\+[1-9]\d{6,14}$ |
+ then up to 15 digits |
| Hex colour | ^#([0-9a-f]{3}|[0-9a-f]{6})$ |
Use with i flag |
| IPv4 address (format only) | ^(\d{1,3}\.){3}\d{1,3}$ |
Allows 999; check ranges in code |
| Trim spaces | ^\s+|\s+$ |
Replace with empty string |
| Multiple spaces | {2,} |
Replace with one space |
Pitfalls
- Forgetting anchors.
\d{5}also matches inside “123456789”. Use^...$for validation. - Unescaped dot.
example.comalso matches “exampleXcom”. Writeexample\.com. - Catastrophic backtracking. Nested quantifiers such as
(a+)+$can take exponential time on certain inputs and freeze a server (ReDoS). Keep patterns specific and test with long non-matching input. - Parsing HTML or JSON with regex. Use a real parser; regex is fine for quick extraction but not for nested structures. See our JSON basics guide.
- Over-strict validation. Names with apostrophes (O’Brien), accented characters and long domain extensions are all valid. Use Unicode-aware patterns (
\p{L}with theuflag) for names. - Escaping in strings. In many languages you write the regex inside a string, so
\dbecomes"\\d". Use raw strings in Python:r"\d+".
Checklist
- Start simple, then add constraints.
- Anchor validation patterns with
^and$. - Escape metacharacters you want literally.
- Prefer lazy or negated classes over greedy
.*. - Test with matching and non-matching examples, including edge cases.
- Test in the same regex flavour as your code.