DevToys Web Pro iconDevToys Web Proوبلاگ
به ما امتیاز دهید:
افزونه مرورگر را امتحان کنید:
← Back to Blog

Regex Cheatsheet: Complete Reference for JavaScript Regular Expressions

20 min read

A complete reference for JavaScript regular expressions — from basic syntax to advanced patterns. Use Regex Tester to try any pattern as you read. Jump to a section:


Anchors

Anchors match a position, not a character.

SyntaxMatchesExample
^Start of string (or line with m flag)/^hello/ matches "hello world", not "say hello"
$End of string (or line with m flag)/world$/ matches "hello world", not "world peace"
\bWord boundary (between \w and \W)/\bcat\b/ matches "cat" but not "catch"
\BNon-word boundary/\Bcat\B/ matches "concatenate"
// Match exact string (anchored both ends)
/^hello world$/.test("hello world")   // true
/^hello world$/.test("hello world!")  // false

// Word boundary: match "cat" as a whole word
const text = "The cat catalog";
text.match(/cat/g)   // ["cat"] — only the standalone word
text.match(/cat/g)        // ["cat", "cat"] — matches inside "catalog" too

Character Classes

Shorthand Classes

SyntaxMatchesEquivalent
.Any character except newline (\n)Use [\s\S] to include newlines
\dDigit[0-9]
\DNon-digit[^0-9]
\wWord character[a-zA-Z0-9_]
\WNon-word character[^a-zA-Z0-9_]
\sWhitespace (space, tab, newline, CR, FF, VT)[ \t\n\r\f\v]
\SNon-whitespace[^ \t\n\r\f\v]
\nNewline
\tTab

Custom Character Classes [...]

SyntaxMatches
[abc]a, b, or c
[^abc]Any character except a, b, or c
[a-z]Any lowercase letter
[A-Z]Any uppercase letter
[0-9]Any digit
[a-zA-Z0-9]Any alphanumeric character
[a-z&&[^aeiou]]Consonants only (not standard JS — use explicit list)
// Match a hex color digit
/[0-9a-fA-F]/.test("f")   // true
/[0-9a-fA-F]/.test("g")   // false

// Match anything except digits
/[^d]+/.exec("abc123")  // ["abc"]

// Inside character class: ^ negates, - is range, ] ends class
// To include literal ], put it first: []abc]
// To include literal -, put it last: [a-z-]  or first: [-a-z]
// To include literal ^, don't put it first: [a^b]

Unicode Categories (with u flag)

// Unicode property escapes require the 'u' flag
/p{Letter}/u.test("é")       // true — matches any Unicode letter
/p{Decimal_Number}/u.test("٣") // true — Arabic-Indic digit 3
/p{Emoji}/u.test("😊")        // true

// Useful properties:
// p{L}  or p{Letter}    — any Unicode letter
// p{N}  or p{Number}    — any Unicode number
// p{Z}  or p{Separator} — any Unicode separator
// p{Sc}                  — currency symbols ($, €, £, ¥)
// p{Script=Latin}        — Latin script characters

Quantifiers

Standard Quantifiers

SyntaxMatchesExample
*0 or more (greedy)/a*/ matches "", "a", "aaa"
+1 or more (greedy)/a+/ matches "a", "aaa", not ""
?0 or 1 (optional)/colou?r/ matches "color" and "colour"
{n}Exactly n times/\d{4}/ matches exactly 4 digits
{n,}n or more times/\d{2,}/ matches 2 or more digits
{n,m}Between n and m times/\d{2,4}/ matches 2–4 digits

Greedy vs Lazy vs Possessive

ModeSyntaxBehaviour
Greedy* + ? {n,m}Match as much as possible, then backtrack
Lazy*? +? ?? {n,m}?Match as little as possible
const html = "<b>bold</b> and <i>italic</i>";

// Greedy: matches from first < to last >
html.match(/<.+>/)[0]   // "<b>bold</b> and <i>italic</i>"

// Lazy: matches from < to nearest >
html.match(/<.+?>/g)    // ["<b>", "</b>", "<i>", "</i>"]

// Practical: extract content between tags
html.match(/<b>(.+?)</b>/)[1]  // "bold"

Groups and References

Capturing Groups (...)

SyntaxDescription
(abc)Capturing group — captures match for backreference
(?:abc)Non-capturing group — groups without capturing
(?<name>abc)Named capturing group
\1 \2Backreference to group 1, 2… within the pattern
\k<name>Named backreference
$1 $2Group reference in replace() string
$<name>Named group reference in replace()
// Capturing group — access via match result
const m = "2026-03-05".match(/(d{4})-(d{2})-(d{2})/);
m[1]  // "2026" (year)
m[2]  // "03"   (month)
m[3]  // "05"   (day)

// Named capturing groups
const m2 = "2026-03-05".match(/(?<year>d{4})-(?<month>d{2})-(?<day>d{2})/);
m2.groups.year   // "2026"
m2.groups.month  // "03"
m2.groups.day    // "05"

// Non-capturing group — group without capturing (for alternation)
/(?:Mr|Mrs|Ms) Smith/.test("Ms Smith")   // true
// (no captured group in result)

// Backreference: match repeated word
/(w+) \1/.test("the the")   // true — matches doubled words
/(w+) \1/.test("the cat")   // false

// Named backreference
/(?<tag>w+)>.*</\k<tag>/.test("<div>hello</div>")  // true
/(?<tag>w+)>.*</\k<tag>/.test("<div>hello</span>") // false

Alternation |

// Match either alternative
/cat|dog/.test("I have a dog")  // true
/cat|dog/.test("I have a cat")  // true

// Alternation with groups
/^(GET|POST|PUT|PATCH|DELETE)$/.test("POST")  // true
/^(GET|POST|PUT|PATCH|DELETE)$/.test("SEND")  // false

// Order matters: first match wins (left to right)
"abc".match(/a|ab/)   // ["a"] — "a" matched first
"abc".match(/ab|a/)   // ["ab"] — "ab" matched first

Lookahead and Lookbehind

Lookaround assertions match a position where a condition is true, without consuming characters. They are zero-width — the characters they check are not included in the match.

TypeSyntaxMatches position where…
Positive lookaheadX(?=Y)X is followed by Y
Negative lookaheadX(?!Y)X is NOT followed by Y
Positive lookbehind(?<=Y)XX is preceded by Y
Negative lookbehind(?<!Y)XX is NOT preceded by Y
// Positive lookahead: match "foo" only when followed by "bar"
"foobar".match(/foo(?=bar)/)   // ["foo"] — Y not included
"foobaz".match(/foo(?=bar)/)   // null

// Negative lookahead: match price digits not followed by %
"$100 50%".match(/d+(?!%)/g)  // ["100"] (50 is excluded)

// Positive lookbehind: match digits preceded by $
"$100 €200".match(/(?<=$)d+/)  // ["100"]

// Negative lookbehind: match digits NOT preceded by $
"$100 200".match(/(?<!$)d+/g)  // ["200"]

// Practical: insert thousands separator
"1234567".replace(/B(?=(d{3})+(?!d))/g, ",")  // "1,234,567"

// Practical: extract value after a label
"Price: 49.99 USD".match(/(?<=Price: )[d.]+/)  // ["49.99"]

// Practical: password validation — must contain digit
/^(?=.*d)/.test("abc123")  // true
/^(?=.*d)/.test("abcdef")  // false

Flags

FlagNameEffect
gGlobalFind all matches, not just first. Enables matchAll().
iCase-insensitivea matches A and a
mMultiline^ and $ match start/end of each line
sDotall. matches newline (\n) too
uUnicodeEnable full Unicode matching and \p{...} properties
vUnicodeSets (ES2024)Superset of u: set operations, string properties
yStickyMatch only at lastIndex, no search forward
dIndices (ES2022)Include start/end indices for each group in match() result
// g — find all matches
"aababc".match(/a/g)     // ["a", "a", "a"]
"aababc".match(/a/)      // ["a"] — only first

// i — case-insensitive
/hello/i.test("Hello World")   // true
/hello/i.test("HELLO")         // true

// m — multiline anchors
const text = "line1
line2
line3";
text.match(/^w+/gm)   // ["line1", "line2", "line3"]
text.match(/^w+/g)    // ["line1"] — only first line start

// s — dotall: . matches newline
/<div>(.*?)</div>/s.exec("<div>
hello
</div>")[1]  // "
hello
"

// u — unicode
/😀/u.test("😀")    // true
/p{Emoji}/u.test("😀")   // true

// d — capture group indices (ES2022)
const result = "foo bar".match(/(?<word>w+)/d);
result.indices.groups.word   // [0, 3] — start and end positions

JavaScript RegExp Methods

MethodReturnsNotes
regex.test(str)booleanDoes the pattern match?
regex.exec(str)array | nullFirst match with groups; advances lastIndex with g
str.match(regex)array | nullWithout g: like exec; with g: all matches, no groups
str.matchAll(regex)iteratorAll matches with groups; requires g flag
str.replace(regex, repl)stringReplace first (or all with g)
str.replaceAll(regex, repl)stringReplace all; requires g flag
str.search(regex)number | -1Index of first match
str.split(regex)arraySplit on pattern
// test: boolean check
/d+/.test("abc123")     // true
/d+/.test("abc")        // false

// exec: access groups one match at a time
const re = /(w+)=(w+)/g;
let m;
while ((m = re.exec("a=1 b=2 c=3")) !== null) {
  console.log(m[1], "→", m[2]);
}
// "a" → "1"
// "b" → "2"
// "c" → "3"

// matchAll: all matches with groups (modern preferred)
const pairs = [...'a=1 b=2 c=3'.matchAll(/(?<key>w+)=(?<val>w+)/g)];
pairs.map(m => ({ [m.groups.key]: m.groups.val }));
// [{ a: "1" }, { b: "2" }, { c: "3" }]

// replace with function
"hello WORLD".replace(/w+/g, w => w[0].toUpperCase() + w.slice(1).toLowerCase());
// "Hello World"

// replace with named group reference
"2026-03-05".replace(
  /(?<y>d{4})-(?<m>d{2})-(?<d>d{2})/,
  "$<d>/$<m>/$<y>"
);  // "05/03/2026"

// split on multiple separators
"one,two;three|four".split(/[,;|]/)   // ["one", "two", "three", "four"]

Escaping Special Characters

These characters have special meaning in regex and must be escaped with \ to match literally:

. ^ $ * + ? { } [ ] \ | ( )
// Match a literal dot (not any character)
/3.14/.test("3.14")   // true
/3.14/.test("3X14")   // false

// Escape user input for use in regex
function escapeRegex(str) {
  return str.replace(/[.*+?^${}()|[]\]/g, '\$&');
}
const userInput = "1+1=2";
new RegExp(escapeRegex(userInput)).test("1+1=2")  // true

Common Pattern Library

Test all patterns in the Regex Tester. Each pattern below is written to be practical over theoretically perfect — regex alone cannot fully validate most formats; use it for filtering and initial validation.

Email Address

// Practical email validation (not RFC 5321 complete, but covers 99.9% of real addresses)
const email = /^[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])?)*.[a-zA-Z]{2,}$/;

email.test("user@example.com")         // true
email.test("user.name+tag@sub.co.uk")  // true
email.test("user@")                    // false
email.test("@example.com")             // false

URL

// Match http/https URLs
const url = /https?://(www.)?[-a-zA-Z0-9@:%._+~#=]{1,256}.[a-zA-Z0-9()]{1,6}([-a-zA-Z0-9()@:%_+.~#?&/=]*)/;

url.test("https://example.com")                     // true
url.test("http://sub.example.co.uk/path?q=1#hash")  // true
url.test("ftp://example.com")                        // false

// Extract all URLs from text
const text = "Visit https://foo.com or http://bar.org for details.";
text.match(/https?://[^s)>]+/g);
// ["https://foo.com", "http://bar.org"]

IPv4 Address

// Match valid IPv4 (0-255 per octet)
const ipv4 = /^((25[0-5]|2[0-4]d|1d{2}|[1-9]d|d).){3}(25[0-5]|2[0-4]d|1d{2}|[1-9]d|d)$/;

ipv4.test("192.168.1.1")   // true
ipv4.test("255.255.255.0") // true
ipv4.test("256.0.0.1")     // false
ipv4.test("192.168.1")     // false

IPv6 Address

// Full and compressed IPv6
const ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|::([0-9a-fA-F]{1,4}:){0,5}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|::)$/;

ipv6.test("2001:db8::1")           // true
ipv6.test("::1")                   // true (loopback)
ipv6.test("fe80::1%eth0")          // false (zone IDs not included)

Date Formats

// ISO 8601: YYYY-MM-DD
const isoDate = /^d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]d|3[01])$/;
isoDate.test("2026-03-05")   // true
isoDate.test("2026-13-01")   // false (month 13)

// US format: MM/DD/YYYY
const usDate = /^(0[1-9]|1[0-2])/(0[1-9]|[12]d|3[01])/d{4}$/;
usDate.test("03/05/2026")    // true

// Flexible: match common separators (-, /, .)
const flexDate = /^d{4}[-/.](0[1-9]|1[0-2])[-/.](0[1-9]|[12]d|3[01])$/;
flexDate.test("2026.03.05")  // true

Time

// 24-hour time HH:MM or HH:MM:SS
const time24 = /^([01]d|2[0-3]):([0-5]d)(:([0-5]d))?$/;
time24.test("23:59")       // true
time24.test("23:59:59")    // true
time24.test("24:00")       // false

// 12-hour time with AM/PM
const time12 = /^(0?[1-9]|1[0-2]):[0-5]ds?(AM|PM|am|pm)$/;
time12.test("12:30 PM")    // true
time12.test("3:00am")      // true

Phone Numbers

// US phone: (123) 456-7890 or 123-456-7890 or +1 123 456 7890
const usPhone = /^(+1s?)?((?d{3})?[s.-]?)d{3}[s.-]?d{4}$/;
usPhone.test("(123) 456-7890")   // true
usPhone.test("+1 123 456 7890")  // true
usPhone.test("123.456.7890")     // true

// International E.164 format
const e164 = /^+[1-9]d{1,14}$/;
e164.test("+12025551234")   // true
e164.test("+447911123456")  // true

Hex Color

// 3 or 6 digit hex colors (with optional #)
const hexColor = /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
hexColor.test("#ff0000")   // true
hexColor.test("#f00")      // true
hexColor.test("ff0000")    // true
hexColor.test("#gggggg")   // false

// Also match 8-digit (with alpha)
const hexColorAlpha = /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;

UUID

// UUID v4 (random)
const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
uuid.test("550e8400-e29b-41d4-a716-446655440000")  // true

// Any UUID version
const anyUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;

Semantic Version

// semver: MAJOR.MINOR.PATCH with optional pre-release and build metadata
const semver = /^(0|[1-9]d*).(0|[1-9]d*).(0|[1-9]d*)(?:-((?:0|[1-9]d*|d*[a-zA-Z-][0-9a-zA-Z-]*)(?:.(?:0|[1-9]d*|d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:+([0-9a-zA-Z-]+(?:.[0-9a-zA-Z-]+)*))?$/;

semver.test("1.0.0")            // true
semver.test("2.3.4-alpha.1")    // true
semver.test("1.0.0+build.123")  // true
semver.test("1.0")              // false

Credit Card Number

// Visa
const visa = /^4[0-9]{12}(?:[0-9]{3})?$/;

// Mastercard
const mastercard = /^5[1-5][0-9]{14}|^2(2[2-9][1-9]|2[3-9][0-9]|[3-6][0-9]{2}|7[01][0-9]|720)[0-9]{12}$/;

// Any major card (strip spaces/dashes first)
const anyCard = /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|6(?:011|5[0-9]{2})[0-9]{12})$/;

// Always strip spaces before testing
"4111 1111 1111 1111".replace(/s/g, "");  // "4111111111111111"

Password Strength Rules

// At least 8 chars, one uppercase, one lowercase, one digit, one special char
const strongPassword = /^(?=.*[a-z])(?=.*[A-Z])(?=.*d)(?=.*[!@#$%^&*()_+-=[]{};':"\|,.<>/?]).{8,}$/;

strongPassword.test("Passw0rd!")   // true
strongPassword.test("password")    // false (no uppercase, digit, special)
strongPassword.test("PASSWORD1!")  // false (no lowercase)

// Check individual rules with separate patterns (better UX than one mega-regex)
const rules = {
  minLength:   str => str.length >= 8,
  hasUpper:    str => /[A-Z]/.test(str),
  hasLower:    str => /[a-z]/.test(str),
  hasDigit:    str => /d/.test(str),
  hasSpecial:  str => /[!@#$%^&*]/.test(str),
};

Slug (URL-Friendly String)

// Valid URL slug: lowercase letters, digits, hyphens
const slug = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
slug.test("my-blog-post")     // true
slug.test("hello-world-2026") // true
slug.test("My Post")          // false

// Convert a string to slug
function toSlug(str) {
  return str
    .toLowerCase()
    .trim()
    .replace(/[^ws-]/g, '')    // remove non-word chars
    .replace(/[s_-]+/g, '-')   // spaces/underscores → hyphens
    .replace(/^-+|-+$/g, '');   // trim leading/trailing hyphens
}
toSlug("Hello, World! 2026")  // "hello-world-2026"

Extract Content Between Tags

// Extract inner HTML of a specific tag
const html = "<p>First</p><p>Second</p>";

// All matches
html.match(/<p>(.*?)</p>/g)          // ["<p>First</p>", "<p>Second</p>"]

// Inner content only (with matchAll)
[...html.matchAll(/<p>(.*?)</p>/g)].map(m => m[1])  // ["First", "Second"]

// Multiline content (requires s flag)
const multi = "<div>
Hello
</div>";
multi.match(/<div>(.*?)</div>/s)[1]  // "
Hello
"

Trim Whitespace Variants

// Trim leading and trailing whitespace (like str.trim())
str.replace(/^s+|s+$/g, '')

// Collapse internal whitespace to single space
str.replace(/s+/g, ' ')

// Remove all whitespace
str.replace(/s/g, '')

// Trim and collapse in one step
str.replace(/^s+|s+$/g, '').replace(/s+/g, ' ')

Multiline Comments

// Strip C-style block comments /* ... */
code.replace(//*[sS]*?*//g, '')

// Strip single-line comments // ...
code.replace(///.*$/gm, '')

// Strip both
code
  .replace(//*[sS]*?*//g, '')
  .replace(///.*$/gm, '')

Debugging Tips

  • Test incrementally — build the pattern piece by piece in Regex Tester with real input, not after writing the full expression.
  • Catastrophic backtracking — patterns like (a+)+ or (\w+\s?)* against a failing string can take exponential time. Avoid nested quantifiers on the same character class.
  • Anchors prevent partial matches — if /\d+/ matches unexpectedly, add ^ and $ to require the whole string to be digits.
  • lastIndex reuse bug — regex objects with g flag maintain state via lastIndex. Calling test() or exec() repeatedly on the same regex instance will cycle through matches. Use regex.lastIndex = 0 to reset, or create a new regex object each time.
  • Flags are case-sensitive/pattern/G is a syntax error; flags must be lowercase.

Try any pattern from this cheatsheet in Regex Tester — paste your pattern and test string to see match highlights, group captures, and flag behavior instantly.