Free tool
Regex cheat sheet
Free · no sign-up · runs in your browser, nothing is uploaded
.Any character except a line break (with the s flag, any character at all)/h.t/gtry it →\dA digit, 0-9/\d+/gtry it →\DAnything except a digit/\D+/gtry it →\wA word character: A-Z, a-z, 0-9 or _/\w+/gtry it →\WAnything except a word character/\W/gtry it →\sWhitespace: space, tab, line breaks and Unicode spaces/\s+/gtry it →\SAnything except whitespace/\S+/gtry it →[abc]One of a, b or c/gr[ae]y/gtry it →[^abc]Any one character except a, b or c/[^aeiou\s]/gtry it →[a-z]One character in the range a to z/[a-f0-9]+/gtry it →[\s\S]Any character including line breaks (works without the s flag)/a[\s\S]b/gtry it →\p{L}A letter in any script (needs the u or v flag)/\p{L}+/gutry it →\p{Script=Greek}A character from one script (u or v flag)/\p{Script=Greek}+/gutry it →[\p{L}--[a-z]]Set difference: letters except a-z (v flag only)/[\p{L}--[a-z]]+/gvtry it →
^Start of the text (start of each line with the m flag)/^\w+/gmtry it →$End of the text (end of each line with the m flag)/\w+$/gmtry it →\bWord boundary: between a word character and a non-word character/\bcat\b/gtry it →\BNot a word boundary/\Bcat/gtry it →
*Zero or more of the previous item/go*gle/gtry it →+One or more/go+gle/gtry it →?Zero or one (optional)/colou?r/gtry it →{3}Exactly 3/\d{3}/gtry it →{2,}2 or more/\d{2,}/gtry it →{2,4}Between 2 and 4/\d{2,4}/gtry it →*? +? ?? {n,m}?Lazy: as few as possible instead of as many/<.+?>/gtry it →
(abc)Capture group: groups and saves the match as $1, $2.../(\d+)-(\d+)/gtry it →(?<name>abc)Named capture group, read as match.groups.name or $<name>/(?<user>\w+)@(?<host>[\w.]+)/gtry it →(?:abc)Non-capturing group: groups without saving/(?:ha)+/gtry it →a|bAlternation: a or b/cat|dog/gtry it →\1Backreference: the same text group 1 matched/(\w)\1/gtry it →\k<name>Backreference to a named group/(?<q>['"]).*?\k<q>/gtry it →(?i:abc)Modifier: turn a flag on (or off with -) inside the group (recent engines only)/(?i:hello) world/gtry it →
(?=abc)Lookahead: followed by abc, without consuming it/\d+(?=px)/gtry it →(?!abc)Negative lookahead: not followed by abc/\d+(?!px|\d)/gtry it →(?<=abc)Lookbehind: preceded by abc/(?<=\$)\d+/gtry it →(?<!abc)Negative lookbehind: not preceded by abc/(?<!\$)\b\d+/gtry it →
\. \* \+ \? \( \) \[ \] \{ \} \| \^ \$ \\ \/A literal special character/\$\d+\.\d{2}/gtry it →\n \r \tLine feed, carriage return, tab/\t/gtry it →\0The NUL character-\xhhThe character with hex code hh/\x41/gtry it →\uhhhhThe UTF-16 code unit hhhh/\u00e9/gtry it →\u{hhhhh}A code point by number (u or v flag)/\u{1F680}/gutry it →\cXA control character, like \cJ for line feed-
$&The whole match-$1 … $99The text of a capture group-$<name>The text of a named group-$`The text before the match-$'The text after the match-$$A literal $-
- Email address (HTML spec)try it →
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/The pattern browsers use for <input type="email">. It accepts user@localhost (no dot needed). Confirm an address by sending an email to it.
Matches: ada@example.com first.last+tag@sub.example.co.uk · Rejects: no-at-sign.example.com two@@example.com space in@example.com
- URL (http or https)try it →
/https?:\/\/[^\s/$.?#][^\s]*/iFinds links in text. To validate one URL, new URL(text) in JavaScript is stricter and handles every edge case.
Matches: https://devhunt.org/free-tools?x=1 http://localhost:3000/path · Rejects: ftp://example.com https:// spaced.com
- IPv4 addresstry it →
/^(?:(?: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)$/Each part is 0-255 with no leading zeros.
Matches: 192.168.1.1 255.255.255.255 0.0.0.0 · Rejects: 256.1.1.1 1.2.3 01.2.3.4
- Date (YYYY-MM-DD)try it →
/^(?<year>\d{4})-(?<month>0[1-9]|1[0-2])-(?<day>0[1-9]|[12]\d|3[01])$/Checks the shape and ranges, not the calendar: 2026-02-31 passes. Parse the date to be sure.
Matches: 2026-10-31 1999-01-01 · Rejects: 2026-13-01 2026-1-5 26-10-31
- Time (24-hour HH:MM, optional :SS)try it →
/^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$/Two-digit hours from 00 to 23.
Matches: 09:30 23:59:59 00:00 · Rejects: 24:00 9:30 12:60
- Hex colortry it →
/^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/Accepts the 3, 4, 6 and 8-digit forms CSS allows (the 4 and 8-digit forms include alpha).
Matches: #fff #FF8800 #ff880080 · Rejects: #ff888 ff8800 #ggg
- UUIDtry it →
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iRFC 9562 UUIDs, versions 1 to 8, with the variant bits 10xx. The nil and max UUIDs are special cases it rejects.
Matches: 123e4567-e89b-42d3-a456-426614174000 0190B9C1-7F3A-7C2E-9A1B-3C4D5E6F7A8B · Rejects: 123e4567e89b42d3a456426614174000 123e4567-e89b-92d3-a456-426614174000
- URL slugtry it →
/^[a-z0-9]+(?:-[a-z0-9]+)*$/Lowercase letters and digits, separated by single hyphens.
Matches: regex-tester top-10-tools · Rejects: Regex-Tester double--dash -leading
- Username (3-16 characters)try it →
/^[a-zA-Z0-9_]{3,16}$/Letters, digits and underscores. Change {3,16} to your own limits.
Matches: john_rush dev42 · Rejects: ab has space way_too_long_username_here
- Password rule (12+ characters, mixed)try it →
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\w\s]).{12,}$/Each lookahead checks one rule. NIST SP 800-63B advises length over composition rules, so consider a length check alone.
Matches: Correct-Horse-9 S3cure!Passphrase · Rejects: alllowercase123! Short1! NoDigitsHere!!
- Phone number (E.164)try it →
/^\+[1-9]\d{1,14}$/The international format: a plus, a country code and at most 15 digits in total, no spaces.
Matches: +14155552671 +442071838750 · Rejects: 14155552671 +0123456 +1 415 555 2671
- Phone number (US)try it →
/^(?:\+1[ .-]?)?\(?\d{3}\)?[ .-]?\d{3}[ .-]?\d{4}$/Accepts common US formats. For real validation of any country, use a library such as libphonenumber.
Matches: (415) 555-2671 415.555.2671 +1 415 555 2671 · Rejects: 555-2671 415-555-26711
- Semantic version (semver.org)try it →
/^(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:-(?<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/The official pattern from semver.org, with named groups for each part.
Matches: 1.0.0 2.10.3-beta.1+build.42 · Rejects: 1.0 01.0.0 v1.0.0
- MAC addresstry it →
/^(?:[0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}$/Six pairs of hex digits separated by colons or hyphens.
Matches: 00:1A:2B:3C:4D:5E 00-1a-2b-3c-4d-5e · Rejects: 001A2B3C4D5E 00:1A:2B:3C:4D
- Number (integer or decimal)try it →
/^-?\d+(?:\.\d+)?$/No exponent, no thousands separators. Number(text) is often simpler.
Matches: 42 -3.14 0.5 · Rejects: .5 1. 1e5
- Add thousands separatorstry it →
/\B(?=(\d{3})+(?!\d))/Replace with "," to turn 1234567 into 1,234,567. In real code, Intl.NumberFormat also handles locales.
Matches: 1234567 · Rejects: 123
- Repeated wordtry it →
/\b(\w+)\s+\1\b/iA backreference: \1 must match the same text as group 1.
Matches: this is is a typo The the start · Rejects: no repeats here
- Leading and trailing whitespacetry it →
/^\s+|\s+$/Replace with nothing to trim. String.prototype.trim() does the same.
Matches: padded · Rejects: tight
- HTML tagtry it →
/<\/?([a-zA-Z][a-zA-Z0-9-]*)\b[^>]*>/Fine for quick searches. To read or clean HTML, use a parser (DOMParser, or DOMPurify for untrusted input).
Matches: <div class="x"> </p> <my-element> · Rejects: a < b > c
- Log line (date, time, level, message)try it →
/^(?<date>\d{4}-\d{2}-\d{2}) (?<time>\d{2}:\d{2}:\d{2}) (?<level>[A-Z]+) (?<msg>.*)$/Named groups pull each field out; adjust the parts to your log format.
Matches: 2026-10-31 09:15:02 ERROR Payment failed · Rejects: Payment failed at 09:15
- camelCase word boundariestry it →
/(?<=[a-z0-9])(?=[A-Z])/An empty match between a lowercase letter and an uppercase one. Replace with a space or split on it.
Matches: camelCaseString · Rejects: lowercase
- Emojitry it →
/\p{Extended_Pictographic}/uNeeds the u or v flag. Some emoji are several code points joined together (like 👩💻), and match more than once.
Matches: Ship it 🚀 Thanks ❤️ · Rejects: plain text
Regex flags
In JavaScript, flags go after the closing slash: /cat/gi. Python passes them as arguments (re.I, re.M, re.S), and PHP puts them after its delimiter ('/cat/i').
| Flag | Name | What it does |
|---|---|---|
| g | global | Find every match, not just the first. |
| i | ignoreCase | Ignore upper and lower case. |
| m | multiline | ^ and $ match at the start and end of each line. |
| s | dotAll | . also matches line breaks. |
| u | unicode | Unicode mode: code points, \u{...} and \p{...}, stricter syntax. |
| v | unicodeSets | Unicode sets: like u, plus set operations in classes ([\p{L}--[a-z]]). |
| y | sticky | Match only at lastIndex, with no searching ahead. |
| d | hasIndices | Report the start and end of every group (match.indices). |
Greedy vs lazy matching
Quantifiers are greedy by default: they match as much as they can and give characters back only when the rest of the pattern fails. Add ? after a quantifier to make it lazy, so it matches as little as it can:
"<b>bold</b>".match(/<.+>/)[0] // "<b>bold</b>" greedy "<b>bold</b>".match(/<.+?>/)[0] // "<b>" lazy "<b>bold</b>".match(/<[^>]+>/)[0] // "<b>" a negated class, often faster
A negated class like [^>]+ says exactly what may not appear, so the engine never has to backtrack. Prefer it when you know the closing character. Try the lazy version.
Which characters need escaping
Outside a character class, these have a special meaning and need a backslash to match literally: . * + ? ^ $ { } ( ) [ ] | \, and / inside a JavaScript regex literal. Inside [...], only \, ], a ^ at the start and a - between two characters are special.
When the pattern is a string, as in new RegExp("\\d+\\.\\d+") or most other languages, the backslashes are doubled because the string literal uses one. Python's raw strings (r"\d+") avoid that. To turn user input into a literal pattern, escape it first:
// Every regex special character gets a backslash
const escapeRegex = s => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
new RegExp(escapeRegex("1+1=2?")) // /1\+1=2\?/The string escape tool does the same for regex and many other formats.
How regex differs between languages
The tokens above are JavaScript syntax. The basics carry over to other languages, but the advanced parts do not always. The main differences:
| Feature | JavaScript | Python re | PCRE (PHP) | Java | Go (RE2) |
|---|---|---|---|---|---|
| Named group | (?<n>…) | (?P<n>…) | (?<n>…) or (?P<n>…) | (?<n>…) | (?P<n>…), (?<n>…) since 1.22 |
| Lookahead (?=…) | Yes | Yes | Yes | Yes | No |
| Lookbehind (?<=…) | Yes, any length | Fixed width only | Yes, with length limits | Bounded length only | No |
| Backreference \1 | Yes | Yes | Yes | Yes | No |
| Atomic group (?>…), possessive a++ | No | Yes, Python 3.11+ | Yes | Yes | No |
| Inline flags (?i) | Only as (?i:…) in recent engines | Yes | Yes | Yes | Yes |
| \d matches non-ASCII digits | No | Yes (str patterns) | No by default | No by default | No |
| Unicode properties \p{L} | With u or v flag | No (third-party regex module) | Yes | Yes | Yes |
Go's RE2 engine trades features for a guarantee: matching always takes time linear in the length of the input, so it cannot suffer from catastrophic backtracking. JavaScript, Python, PCRE and Java are backtracking engines, where a badly written pattern can take exponential time.
POSIX classes for grep, sed and awk
Command line tools use POSIX regular expressions. Basic (BRE) and extended (ERE, grep -E, sed -E) syntax have no \d, \w or lazy quantifiers. Use bracket expressions instead, which also follow the current locale:
| POSIX class | Roughly the same as | Example |
|---|---|---|
| [[:digit:]] | [0-9] | grep -E "^[[:digit:]]+$" |
| [[:alpha:]] | [A-Za-z] (plus locale letters) | grep -E "[[:alpha:]]+" |
| [[:alnum:]] | [A-Za-z0-9] | sed -E "s/[^[:alnum:]]+/-/g" |
| [[:space:]] | space, tab, line breaks | grep -E "[[:space:]]+$" |
| [[:upper:]] [[:lower:]] | [A-Z] and [a-z] | grep -E "^[[:upper:]]" |
| [[:punct:]] | punctuation like ! , . ; | tr -d "[:punct:]" |
GNU grep also has grep -P for Perl-compatible syntax, where \d and lookarounds work. In BRE, + ? | ( ) { } are literal unless escaped; ERE makes them special, like in JavaScript.
About the common patterns
Each pattern in the list above is tested against the examples shown next to it, and the notes say what it does not check. A few rules hold for all of them:
- Validation patterns are anchored with
^and$. Without the anchors they would find a match inside longer text. - The email pattern is the one the HTML spec uses for
<input type="email">. No regex can tell you whether a mailbox exists; only sending a message can. - A date pattern checks the shape, not the calendar. Parse the result with a date library to reject 2026-02-31.
- For URLs, HTML and phone numbers, a parser is more reliable than a regex:
new URL(),DOMParserand libphonenumber.
To test your own variations, open any pattern in the regex tester. For other developer references, see the HTTP status codes list, or browse the code tools directory on DevHunt.
More free developer tools
Looking for a full product instead? See testing tools on DevHunt.
FAQ
What does .* mean in regex?+
The dot matches any one character except a line break, and * repeats it zero or more times, so .* matches any run of characters on a line, including none. It is greedy: it takes as much as it can, then gives back only what the rest of the pattern needs. Use .*? to take as little as possible.
What do ^ and $ mean?+
^ matches at the start of the text and $ at the end. With the m (multiline) flag they match at the start and end of every line. Inside a character class, a ^ right after [ means "not": [^0-9] is any character that is not a digit.
What is the difference between \d and [0-9]?+
In JavaScript they are the same: \d only matches the ASCII digits 0 to 9, even with the u flag. In Python 3 and .NET, \d also matches digits from other scripts, such as Arabic-Indic digits, so [0-9] is the safe choice when you mean ASCII digits only.
How do I match a literal dot, bracket or other special character?+
Put a backslash in front of it: \. for a dot, \( for a parenthesis, \[ for a bracket, \\ for a backslash. The characters that need escaping outside a class are . * + ? ^ $ { } ( ) [ ] | \ and, in a regex literal, /. Inside [...] most of them lose their meaning, so [.] is also a literal dot.
What does ?: mean in a regex?+
(?:...) is a non-capturing group. It groups part of the pattern, for example to repeat it or to limit an alternation, without saving the match as $1. (?:ha)+ matches "hahaha" and has no capture groups.
What is the difference between greedy and lazy quantifiers?+
A greedy quantifier (*, +, ?, {n,m}) matches as much as possible, a lazy one (*?, +?, ??, {n,m}?) as little as possible. On "<b>bold</b>", <.+> matches the whole string, while <.+?> matches "<b>" and then "</b>".
How do I match a whole word only?+
Wrap the word in word boundaries: \bcat\b matches "cat" but not "concat" or "cats". \b sits between a word character (letter, digit, underscore) and anything else. In JavaScript it is ASCII only, so it does not treat accented letters as word characters.
Is regex the same in every programming language?+
The basics are: classes, anchors, quantifiers, groups and alternation work almost everywhere. The differences are in advanced features: named group syntax, lookbehind limits, atomic groups, Unicode handling and inline flags. Go and RE2 leave out lookarounds and backreferences entirely. The flavor table on this page lists the main differences.
Sources: MDN: Regular expressions cheat sheet · MDN: RegExp flags · Python re · Go regexp/syntax · PCRE2 pattern syntax · Java Pattern · POSIX regular expressions · HTML spec: valid email address · semver.org. Checked October 2026.