← Blog · May 12, 2026 · dev, regex

JavaScript Regex Cheatsheet: Patterns You Actually Use

After years of writing regex, you reach for the same dozen patterns over and over. The other thousand symbols in the regex spec? You look them up. Here's the practical subset every JavaScript developer ends up memorizing.

All examples here are JavaScript regex (ECMAScript). Try them in our regex tester.

The character class basics

\d     digit (0-9)
\D     non-digit
\w     word character (a-z, A-Z, 0-9, _)
\W     non-word
\s     whitespace (space, tab, newline)
\S     non-whitespace
.      any character except newline
[abc]  any of a, b, or c
[^abc] anything except a, b, c
[a-z]  any lowercase letter

Quantifiers

*       0 or more (greedy)
+       1 or more
?       0 or 1
{n}     exactly n
{n,}    n or more
{n,m}   between n and m
*?      0 or more (lazy / non-greedy)
+?      1 or more (lazy)

Anchors

^   start of string (or line with /m flag)
$   end of string (or line with /m flag)
\b  word boundary
\B  non-word boundary

The patterns you actually reuse

Email (simple but practical)

/^[\w.+-]+@[\w-]+(\.[\w-]+)+$/

The full RFC 5322 regex is 600+ characters and matches things you don't actually want to accept. This simple version handles 99.9% of real-world emails. For deeper validation try our email validator.

US phone number

/^\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$/

Matches (555) 123-4567, 555-123-4567, 555.123.4567, 555 123 4567, 5551234567.

URL

/^https?:\/\/[\w.-]+(?:\.[\w.-]+)+[\w\-._~:/?#[\]@!$&'()*+,;=.]+$/

Practical match. For parsing URL parts, use our URL parser instead.

ISO date (YYYY-MM-DD)

/^\d{4}-\d{2}-\d{2}$/

Hex color

/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/

Matches #fff, #ffffff, fff, ffffff. Use our color converter to play with values.

UUID (v4)

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

The 4 in the third group and the [89ab] in the fourth enforce v4-specific structure.

Strip HTML tags

text.replace(/<[^>]+>/g, '')

Quick way to remove tags. Doesn't handle entities or attributes with > in them. For better stripping see our strip HTML tool.

Slug from title

title
  .toLowerCase()
  .replace(/[^a-z0-9\s-]/g, '')
  .replace(/\s+/g, '-')
  .replace(/-+/g, '-');

Or use our slug generator which adds Unicode normalization.

Capture groups

// Unnamed groups
const m = 'John Doe'.match(/(\w+) (\w+)/);
m[1] // 'John'
m[2] // 'Doe'

// Named groups (modern JS)
const m2 = 'John Doe'.match(/(?<first>\w+) (?<last>\w+)/);
m2.groups.first // 'John'
m2.groups.last  // 'Doe'

// Non-capturing
/(?:abc)def/  // (?:...) doesn't create a capture group

Lookaround

// Positive lookahead — match X followed by Y, capture only X
/\d+(?=px)/  matches '15' in '15px'

// Negative lookahead — match X NOT followed by Y
/\d+(?!px)/  matches '15' in '15em' but not '15px'

// Lookbehind (newer JS)
/(?<=\$)\d+/   matches '99' in '$99' but not in '99 dollars'
/(?<!\$)\d+/   matches '99' in '99 dollars' but not in '$99'

JavaScript-specific gotchas

  1. Always use new RegExp() for dynamic patterns. new RegExp(userInput) lets users inject regex. Escape with s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').
  2. The /g flag is stateful. regex.test() with /g advances lastIndex between calls. Be careful in loops.
  3. String.match() vs String.matchAll(). Without /g, match() returns capture groups. With /g, match() loses capture groups (just returns matched strings). Use matchAll() for groups + all matches.
  4. Catastrophic backtracking. Patterns like (a+)+ on bad input can hang forever. Avoid nested quantifiers. Test your patterns with malicious inputs.

Tools

← All blog posts