Regex Cheat Sheet

A regular expression is a pattern for matching text. \d matches a digit, \w a word character, + means one or more, ? makes something optional, and ^ and $ pin the match to the start and end. Below are the full syntax and 30 tested patterns, each checked live against strings that should and should not match.

Six symbols that cover most patterns
SymbolMeans
\dA digit 0-9
\wLetter, digit or underscore
+One or more of the previous item
?The previous item is optional
[ ]One character from a set
^ $Start and end of the text

Updated

Copy a pattern, then try your own text against it in the box beside it. Every pattern on this page ships with examples that must match and examples that must not, and the page runs them in your browser so you can see each result.

Syntax

Regex syntax reference (JavaScript flavour)
SyntaxMatchesExampleExample matches
.Any character except a line breakc.tcat, cot, c9t
\d \DA digit / anything but a digit\d\d42
\w \WLetter, digit or underscore / anything else\w+user_1
\s \SWhitespace / anything but whitespacea\sba b
[abc]One of the listed charactersgr[ae]ygray, grey
[^abc]Any character not listed[^0-9]x
[a-z]A character in the range[A-F0-9]B, 7
^ $Start / end of the string (or line with m)^Hi$Hi on its own
\bA word boundary\bcat\bcat, not category
*0 or more of the previous itemab*cac, abbc
+1 or moreab+cabc, abbbc
?0 or 1 (optional)colou?rcolor, colour
{n} {n,} {n,m}Exactly n, n or more, between n and m\d{3,4}123, 1234
*? +?Lazy: as few as possible<.+?><b> in <b>x</b>
(abc)Capture group(\d+)pxgroup 1 = 24 in 24px
(?:abc)Group without capturing(?:ab)+abab
(?<name>abc)Named capture group(?<year>\d{4})groups.year = 2026
\1Back-reference to group 1(\w)\1ll in hello
a|bEither sidecat|dogcat, dog
(?=x) (?!x)Followed by / not followed by x\d+(?=px)24 in 24px
(?<=x) (?<!x)Preceded by / not preceded by x(?<=\$)\d+30 in $30
\p{L}Any letter in any script (needs u flag)\p{L}+café, Ελλάδα

Flags

JavaScript flags
FlagNameEffect
gglobalFind every match, not just the first
iignore caseA matches a
mmultiline^ and $ match at each line
sdotAll. also matches line breaks
uunicodeFull Unicode, enables \p{...}
ystickyMatch only at lastIndex
dindicesReport start and end of each group
vunicodeSetsNewer Unicode mode with set operations in classes

30 tested patterns

Email address (practical)

/^[^\s@]+@[^\s@.]+(?:\.[^\s@.]+)+$/

Something, an @, then a domain with at least one dot. No spaces. No regex fully checks an email address. Send a confirmation email to know it is real.

Should match: "[email protected]", "[email protected]", "[email protected]". Should not match: "ana@example", "ana [email protected]", "@example.com", "[email protected]", "ana@@example.com".

Web address (http or https)

/^https?:\/\/[\w-]+(?:\.[\w-]+)+(?::\d{1,5})?(?:[/?#][^\s]*)?$/i

http or https, a host with at least one dot, an optional port, then any path, query or fragment without spaces. In JavaScript, new URL(value) inside a try block is the stricter check.

Should match: "https://we.inc", "http://example.com:8080/a/b?x=1#top", "https://sub.example.co.uk/path". Should not match: "ftp://example.com", "https://localhost", "https://exa mple.com", "example.com".

Domain name

/^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/i

Labels of letters, digits and inner hyphens, separated by dots, ending in a letters-only top-level domain.

Should match: "we.inc", "my-site.example.com", "a.io". Should not match: "-bad.com", "bad-.com", "no_underscores.com", "localhost", "example.c".

URL slug

/^[a-z0-9]+(?:-[a-z0-9]+)*$/

Lower-case letters and digits in groups joined by single hyphens.

Should match: "regex-cheat-sheet", "page2", "a-b-c". Should not match: "Regex-Cheat", "double--hyphen", "-leading", "trailing-", "with space".

Phone number, international (E.164)

/^\+[1-9]\d{6,14}$/

A plus sign, a country code that does not start with 0, and 7 to 15 digits in total, no spaces. Strip spaces, dashes and brackets first. For real validation per country, use a phone library.

Should match: "+14155550123", "+447911123456", "+923001234567". Should not match: "14155550123", "+0123456789", "+1 415 555 0123", "+12345".

Phone number, US and Canada

/^(?:\+?1[\s.-]?)?\(?([2-9]\d{2})\)?[\s.-]?([2-9]\d{2})[\s.-]?(\d{4})$/

Optional +1, a 3-digit area code and exchange that do not start with 0 or 1, then 4 digits, with common separators.

Should match: "(415) 555-0123", "415.555.0123", "+1 415 555 0123", "4155550123". Should not match: "(015) 555-0123", "415-155-0123", "555-0123", "415-555-012".

US ZIP code

/^\d{5}(?:-\d{4})?$/

Five digits, optionally followed by a hyphen and four more (ZIP+4).

Should match: "94103", "94103-1234". Should not match: "9410", "941031", "94103-12", "ABCDE".

UK postcode

/^[A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2}$/i

One or two letters, a digit, an optional letter or digit, an optional space, then a digit and two letters. Checks the shape only. It accepts some codes that do not exist.

Should match: "SW1A 1AA", "M1 1AE", "ec1a1bb", "B33 8TH". Should not match: "SW1A", "1AA SW1", "SW1A 1A", "SW1A-1AA".

Canadian postal code

/^[ABCEGHJ-NPRSTVXY]\d[ABCEGHJ-NPRSTV-Z] ?\d[ABCEGHJ-NPRSTV-Z]\d$/i

Letter, digit, letter, optional space, digit, letter, digit. The letters D, F, I, O, Q and U are never used, and W and Z never come first.

Should match: "K1A 0B1", "M5V3L9", "h2x 1y4". Should not match: "D1A 0B1", "W1A 0B1", "K1A0B", "123 456".

HEX colour

/^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i

A # then 3, 4, 6 or 8 hexadecimal digits (the 4 and 8 forms include transparency).

Should match: "#fff", "#4F98FB", "#4F98FB80", "#abcd". Should not match: "4F98FB", "#ggg", "#12345", "#1234567".

Password with mixed characters

/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^A-Za-z\d]).{12,}$/

At least 12 characters, with a lower-case letter, an upper-case letter, a digit and a symbol, checked by lookaheads. Length matters more than mixing. Many teams now require only a minimum length and check against breached-password lists.

Should match: "Correct-Horse7", "Tr0ub4dor&3xyz". Should not match: "short1A!", "alllowercase1!", "NoDigitsHere!!", "NoSymbols12345".

Username

/^(?=.{3,20}$)[a-z0-9]+(?:[._][a-z0-9]+)*$/i

3 to 20 characters of letters and digits; dots and underscores allowed only between them, never doubled.

Should match: "ana", "ana.lee", "dev_2026". Should not match: "an", ".ana", "ana..lee", "ana_", "this_is_far_too_long_1".

IPv4 address

/^(?:(?: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)$/

Four numbers from 0 to 255 separated by dots, with no leading zeros.

Should match: "192.168.1.1", "8.8.8.8", "255.255.255.255", "0.0.0.0". Should not match: "256.1.1.1", "192.168.1", "01.2.3.4", "1.2.3.4.5".

Date, ISO 8601 (YYYY-MM-DD)

/^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$/

Four-digit year, month 01 to 12, day 01 to 31. It allows 2026-02-31. Parse the date afterwards to reject days that do not exist.

Should match: "2026-10-13", "1999-01-31". Should not match: "2026-13-01", "2026-1-5", "26-10-13", "2026-10-32".

Time, 24-hour (HH:MM)

/^(?:[01]\d|2[0-3]):[0-5]\d$/

Hours 00 to 23, a colon, minutes 00 to 59.

Should match: "00:00", "09:30", "23:59". Should not match: "24:00", "9:30", "12:60", "12-30".

Time, 12-hour with am or pm

/^(?:0?[1-9]|1[0-2]):[0-5]\d\s?[ap]\.?m\.?$/i

Hours 1 to 12, minutes, then am or pm with optional dots and space.

Should match: "9:30 am", "12:00PM", "07:45 p.m.". Should not match: "13:00 pm", "0:30 am", "9:30", "9:3 am".

Whole number

/^-?(?:0|[1-9]\d*)$/

Optional minus sign, then 0 or a number without leading zeros.

Should match: "0", "42", "-17". Should not match: "007", "4.2", "+5", "".

Decimal number

/^-?(?:0|[1-9]\d*)(?:\.\d+)?$/

A whole number with an optional dot and at least one digit after it.

Should match: "3.14", "-0.5", "10". Should not match: ".5", "5.", "1,5", "01.5".

Price with thousands separators

/^\$?(?:\d{1,3}(?:,\d{3})*|\d+)(?:\.\d{2})?$/

Optional dollar sign, digits with correct comma groups (or none), optional two-digit cents.

Should match: "$1,299.00", "1299", "$0.99", "12,345,678". Should not match: "$1,29.00", "1,2345", "$12.5", "$".

Percentage 0 to 100

/^(?:100(?:\.0+)?|\d{1,2}(?:\.\d+)?)%$/

A number from 0 to 100 with optional decimals, followed by %.

Should match: "0%", "45.5%", "100%". Should not match: "101%", "45", "-5%", "100.5%".

Card number shape (13 to 19 digits)

/^(?:\d[ -]?){12,18}\d$/

13 to 19 digits, optionally grouped with spaces or dashes. Shape only. Use the Luhn check and your payment provider to validate a card.

Should match: "4242 4242 4242 4242", "4242-4242-4242-4242", "4242424242424242". Should not match: "4242 4242", "4242 4242 4242 4242", "abcd efgh ijkl mnop".

Semantic version

/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[\da-z-]+(?:\.[\da-z-]+)*)?(?:\+[\da-z-]+(?:\.[\da-z-]+)*)?$/i

MAJOR.MINOR.PATCH without leading zeros, with optional -prerelease and +build parts.

Should match: "1.0.0", "2.13.4-beta.1", "0.1.0+build.7". Should not match: "1.0", "01.0.0", "1.0.0-", "v1.0.0".

UUID

/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i

8-4-4-4-12 hex digits with a version digit from 1 to 8 and the standard variant.

Should match: "3f2b8c1e-7d4a-4e9b-8c21-5a6f0d9e1b23", "018f3c2a-9b7e-7c11-a2b3-4c5d6e7f8091". Should not match: "3f2b8c1e7d4a4e9b8c215a6f0d9e1b23", "3f2b8c1e-7d4a-0e9b-8c21-5a6f0d9e1b23", "3f2b8c1e-7d4a-4e9b-cc21-5a6f0d9e1b23".

Simple HTML tag

/^<([a-z][a-z0-9-]*)(?:\s[^<>]*)?>[^<]*<\/\1>$/i

An opening tag, text without other tags, and the matching closing tag (the \1 back-reference repeats the name). Do not parse full HTML with regex. Use DOMParser or an HTML parser.

Should match: "<b>bold</b>", "<a href=\"/x\">link</a>", "<my-card>hi</my-card>". Should not match: "<b>bold</i>", "<b>bold", "<b><i>x</i></b>".

Blank or whitespace only

/^\s*$/

Nothing but spaces, tabs or line breaks. Useful to reject empty form fields.

Should match: "", " ", "\t\n". Should not match: " a ", "0".

Hashtag

/^#[\p{L}\p{N}_]+$/u

A # followed by letters (in any script), digits or underscores. Needs the u flag for \p{L}.

Should match: "#webdesign", "#café", "#2026_goals". Should not match: "#", "#web design", "webdesign", "#hello!".

YouTube video address

/^https?:\/\/(?:www\.|m\.)?(?:youtube\.com\/(?:watch\?v=|embed\/|shorts\/)|youtu\.be\/)([\w-]{11})(?:[&?#].*)?$/

The common watch, embed, shorts and short-link forms. Group 1 captures the 11-character video ID.

Should match: "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "https://youtu.be/dQw4w9WgXcQ?t=42", "https://youtube.com/shorts/dQw4w9WgXcQ". Should not match: "https://vimeo.com/123456", "https://youtube.com/watch?v=short", "https://www.youtube.com/channel/abc".

Image file name

/^[^\\/:*?"<>|]+\.(?:jpe?g|png|gif|webp|avif|svg)$/i

A file name without characters that are not allowed in paths, ending in a common image extension.

Should match: "photo.jpg", "Hero Image.WEBP", "logo.svg". Should not match: "photo.pdf", "photo", "bad/name.png", "photo.jpg.exe".

Social handle (@name)

/^@[a-z0-9_]{1,15}$/i

An @ and 1 to 15 letters, digits or underscores, the rule X (formerly Twitter) uses.

Should match: "@wedotinc", "@a_b_c", "@User123". Should not match: "wedotinc", "@", "@has-dash", "@this_handle_is_too_long".

Repeated word

/\b(\w+)\s+\1\b/i

Finds a word typed twice in a row, such as 'the the'. Not anchored, so it searches inside text.

Should match: "This is the the end", "It was was fine". Should not match: "This is the end", "the theme".

JavaScript, Python and PHP

The same ideas in JavaScript, Python and PHP
TaskJavaScriptPython (re)PHP (preg)
Write a pattern/\d+/g or new RegExp("\\d+", "g")r"\d+" (raw string)'/\d+/' (needs delimiters)
Test a whole value/^\d+$/.test(s)re.fullmatch(r"\d+", s)preg_match('/^\d+$/', $s)
Find all matchess.matchAll(/\d+/g)re.findall(r"\d+", s)preg_match_all('/\d+/', $s, $m)
Replace alls.replace(/\d+/g, "#")re.sub(r"\d+", "#", s)preg_replace('/\d+/', '#', $s)
Named group(?<year>\d{4})(?P<year>\d{4})(?<year>\d{4}) or (?P<year>\d{4})
Ignore casei flagre.IGNORECASEi modifier
Unicode letters \p{L}Needs the u flagNot in re; use the regex packageNeeds the u modifier
LookbehindSupported, any lengthSupported, fixed length onlySupported, fixed length in most versions

Reading a pattern from left to right

Take ^\d{5}(-\d{4})?$, the US ZIP code pattern. ^ says start here. \d{5} is exactly five digits. The group (-\d{4}) is a hyphen and four digits, and the ? after it makes that whole group optional. $ says the text must end there. Put together: five digits, optionally followed by a hyphen and four more, and nothing else.

Almost every pattern breaks down the same way: anchors, then pieces, each followed by how many times it can repeat. When a pattern looks unreadable, split it at the groups and read each piece on its own.

Common mistakes

Forgetting ^ and $ when validating. /\d{5}/ accepts abc123456xyz because it finds five digits inside it.

Leaving a dot unescaped. example.com as a pattern also matches exampleXcom; write example\.com.

Greedy matching across too much text. <.+> on <b>a</b> matches the whole string; use <.+?> or [^>]+.

Reusing a regex with the g flag in .test(). It remembers lastIndex, so a second call on the same string can return false.

Nesting quantifiers such as (a+)+. On some inputs this takes exponential time and can freeze a page or server.

Building a pattern from user input without escaping it. Characters like . * ( ) change its meaning.

How it works

  1. Use the syntax table to look up any symbol, and the flags table for g, i, m, s, u and the rest.
  2. Find a pattern in the list. The ticks and crosses show its built-in examples being tested live.
  3. Type your own value in the test box under a pattern to see whether it matches.
  4. Copy the pattern as a JavaScript literal. The language table shows how to use it in Python and PHP.

Tips

Frequently asked questions

What is the best regex for email addresses?

A practical one is ^[^\s@]+@[^\s@.]+(\.[^\s@.]+)+$: some text, an @, and a domain with at least one dot. It catches typos without rejecting unusual but valid addresses. No regex can tell whether an address really exists, so send a confirmation email.

How do I match a phone number with regex?

Remove spaces, dashes and brackets, then check the E.164 format: ^\+[1-9]\d{6,14}$. For US and Canadian numbers typed with separators, use the North American pattern on this page. For full checking per country, a phone number library is more reliable.

What does ^ mean in regex?

Outside square brackets, ^ anchors the match to the start of the text, or of each line with the m flag. Inside square brackets as the first character, as in [^0-9], it means not any of these characters.

Why does my regex work in JavaScript but not in Python?

The flavours differ in details: Python writes named groups as (?P<name>...), does not support \p{L} in its built-in re module, and only allows fixed-length lookbehind. Check the language table on this page for the common differences.

What is the difference between greedy and lazy?

Greedy quantifiers like * and + take as much text as they can and then back off. Adding ? makes them lazy, so they take as little as possible. On <b>x</b><b>y</b>, <.+> matches everything, while <.+?> matches just <b>.

Related: Regex tester, Regex generator, Markdown cheat sheet, Cron expression generator, All free tools.

Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.

More in Guides

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap