Regex cheat sheet
| Syntax | Meaning |
|---|---|
. |
Any character except a line break (with the s flag, including line breaks) |
\d \w \s |
Digit, word character [A-Za-z0-9_], whitespace |
\D \W \S |
Not a digit, not a word character, not whitespace |
[abc] [^abc] [a-z] |
Any of a, b or c; anything except them; a range |
^ $ |
Start and end of the input (of each line with the m flag) |
\b |
Word boundary |
* + ? |
0 or more, 1 or more, 0 or 1 |
{3} {2,} {2,5} |
Exactly 3, at least 2, between 2 and 5 |
*? +? ?? |
Lazy versions: match as few as possible |
(abc) |
Capturing group, referenced as $1 in replacements |
(?<name>abc) |
Named group, referenced as $<name> |
(?:abc) |
Group without capturing |
a|b |
a or b |
(?=abc) (?!abc) |
Lookahead: followed by / not followed by abc |
(?<=abc) (?<!abc) |
Lookbehind: preceded by / not preceded by abc |
\1 \k<name> |
Backreference to a group’s match |
\p{L} \p{Emoji} |
Unicode property classes (needs the u flag) |
Special characters . * + ? ^ $ { } ( ) [ ] | \ must be escaped with a backslash to match literally.
Common patterns
| Pattern | Regex |
|---|---|
|
Email (practical)
Rejects obvious mistakes; real validation is sending an email. |
^[^\s@]+@[^\s@]+\.[^\s@]+$ |
|
URL
Finds http and https links in text. |
https?:\/\/[^\s/$.?#].[^\s]* |
|
IPv4 address
Each octet 0–255. |
\b(?:(?:25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|1?\d?\d)\b |
|
ISO date
YYYY-MM-DD. Doesn’t check that Feb 30 is impossible. |
\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01]) |
|
Hex color
#fff or #1e90ff. |
#(?:[0-9a-fA-F]{3}){1,2}\b |
|
UUID
Use the i flag for uppercase. |
[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} |
|
Semantic version
Groups capture major, minor and patch. |
\bv?(\d+)\.(\d+)\.(\d+)(?:-[\w.]+)?\b |
|
Trailing whitespace
Use with the g and m flags, and replace with nothing. |
[ \t]+$ |
Avoid catastrophic backtracking
A regex like ^(\w+\s?)+$ looks harmless, but on a long string that almost matches, the engine tries
every way of splitting it between the inner and outer +, which takes exponential time. Try it above on
aaaaaaaaaaaaaaaaaaaaaaaaaaaa! and the tester will stop it. To stay safe:
- Don’t nest quantifiers over the same characters: write
^[\w\s]+$instead. - Prefer specific classes like
[^"]*over.*. - Limit input length before matching user-supplied text on a server.
Using regular expressions in JavaScript
const re = /(?<year>\d{4})-(?<month>\d{2})/g;
const text = 'Released 2024-05, updated 2026-10';
re.test(text); // true
text.match(re); // ['2024-05', '2026-10']
for (const m of text.matchAll(re)) {
console.log(m.index, m.groups.year); // 9 '2024', then 26 '2026'
}
text.replace(re, '$<month>/$<year>'); // 'Released 05/2024, updated 10/2026'
// Escape user input before putting it in a regex
const escape = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
A regex with the g flag remembers lastIndex between calls, so calling
re.test() twice on the same string can return true then false. Create a new
regex or reset re.lastIndex = 0.
Frequently asked questions
Which regex flavor does this tester use?
JavaScript (ECMAScript), using your browser’s own engine, so results match what your code does in Chrome, Firefox, Safari, Node.js and Deno. Most syntax is shared with PCRE, Python and Java; the differences are mainly in lookbehind support, named group syntax and flags.
What do the regex flags mean?
g finds all matches instead of the first. i ignores case. m makes ^ and $ match at the start and end of every line. s lets . match line breaks. u enables full Unicode, including \p{…} classes and emoji as single characters. y (sticky) only matches at the current position.
Why does the tester say my pattern was stopped?
Patterns with nested quantifiers like (a+)+, (.*)* or (\w+\s?)+$ can take exponential time on some inputs, called catastrophic backtracking. The tester runs your regex in a background worker and stops it after 1.5 seconds. In production the same pattern could freeze a browser tab or take down a server (ReDoS).
How do I use capture groups in a replacement?
Use $1, $2 … for numbered groups, $<name> for named groups, $& for the whole match and $$ for a literal dollar sign. Turn on Replace in the tester to preview the result. In Python the syntax is \1 and \g<name>.
Why does my regex work here but not in Go?
Go’s regexp package uses RE2, which guarantees linear time by leaving out lookaheads, lookbehinds and backreferences. Patterns using (?=, (?!, (?<=, (?<! or \1 won’t compile in Go. Rewrite them with extra capture groups or code logic.