Free tool

Regex cheat sheet

Every regular expression token in one place: character classes, anchors, quantifiers, groups, lookarounds, escapes and replacement patterns, each with a short example. Click try it on any row to open it in the regex tester with sample text loaded.

Free · no sign-up · runs in your browser, nothing is uploaded

71 entries
Character classes
Anchors and boundaries
Quantifiers
Groups and references
Lookahead and lookbehind
Escapes and special characters
Replacement patterns (String.replace)
  • $&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 $-
Common patterns (tested)
  • 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]*/i

    Finds 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}$/i

    RFC 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/i

    A 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}/u

    Needs 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').

FlagNameWhat it does
gglobalFind every match, not just the first.
iignoreCaseIgnore upper and lower case.
mmultiline^ and $ match at the start and end of each line.
sdotAll. also matches line breaks.
uunicodeUnicode mode: code points, \u{...} and \p{...}, stricter syntax.
vunicodeSetsUnicode sets: like u, plus set operations in classes ([\p{L}--[a-z]]).
ystickyMatch only at lastIndex, with no searching ahead.
dhasIndicesReport 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:

FeatureJavaScriptPython rePCRE (PHP)JavaGo (RE2)
Named group(?<n>…)(?P<n>…)(?<n>…) or (?P<n>…)(?<n>…)(?P<n>…), (?<n>…) since 1.22
Lookahead (?=…)YesYesYesYesNo
Lookbehind (?<=…)Yes, any lengthFixed width onlyYes, with length limitsBounded length onlyNo
Backreference \1YesYesYesYesNo
Atomic group (?>…), possessive a++NoYes, Python 3.11+YesYesNo
Inline flags (?i)Only as (?i:…) in recent enginesYesYesYesYes
\d matches non-ASCII digitsNoYes (str patterns)No by defaultNo by defaultNo
Unicode properties \p{L}With u or v flagNo (third-party regex module)YesYesYes

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 classRoughly the same asExample
[[: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 breaksgrep -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(), DOMParser and 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.

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.