JavaScript logoJavaScriptINTERMEDIATE

JavaScript Regular Expressions

JavaScript regex cheat sheet with pattern syntax, flags, lookaheads, capture groups, common patterns, and practical code examples.

10 min read
regexregexppatternsvalidationjavascripttext-processing

Sign in to mark items as known and track your progress.

Sign in

Basic Patterns

Essential regex patterns and metacharacters

Character Classes

Matching specific sets of characters

📄 Codejavascript
.       Any character except newline
\d      Digit (0-9)
\D      Not a digit
\w      Word character (a-z, A-Z, 0-9, _)
\W      Not a word character
\s      Whitespace (space, tab, newline)
\S      Not whitespace
[abc]   Any of a, b, or c
[^abc]  Not a, b, or c
[a-z]   Character range a to z
[A-Z]   Character range A to Z
[0-9]   Any digit (same as \d)

// Examples
/\d{3}-\d{4}/.test("555-1234")  // true (phone)
/[aeiou]/.test("hello")         // true (vowel)
/[^0-9]/.test("abc")           // true (non-digit)
💡 Dot (.) matches any character except newline - use [\s\S] for all
⚡ Character classes can be negated with ^ inside brackets
📌 \w includes underscore (_) in word characters
🟢 Combine classes: [a-zA-Z0-9] for alphanumeric
character-classesbasics

Anchors

Matching positions in text

📄 Codejavascript
^       Start of string
$       End of string
\b      Word boundary
\B      Not a word boundary

// Multi-line mode (m flag)
^       Start of line
$       End of line

// Examples
/^hello/.test("hello world")     // true
/world$/.test("hello world")     // true
/^hello$/.test("hello")          // true (exact match)
/\bcat\b/.test("cat in hat")     // true (whole word)
/\bcat\b/.test("scatter")        // false
/\Bcat/.test("scatter")          // true (inside word)

// Multi-line examples
const text = "line1\nline2"
/^line2/m.test(text)             // true (with m flag)
/^line2/.test(text)              // false (without m flag)
💡 Use ^ and $ together for exact full string match
⚡ Word boundary \b is zero-width - doesn't consume characters
📌 Multi-line flag (m) changes ^ and $ behavior
🟢 \b is useful for matching whole words only
anchorsboundaries

Quantifiers

Specifying repetition

📄 Codejavascript
*       0 or more
+       1 or more
?       0 or 1
{n}     Exactly n times
{n,}    n or more times
{n,m}   Between n and m times

// Greedy vs Lazy
*?      0 or more (lazy)
+?      1 or more (lazy)
??      0 or 1 (lazy)
{n,}?   n or more (lazy)

// Examples
/ab*c/.test("ac")        // true (0 b's)
/ab+c/.test("ac")        // false (needs 1+ b's)
/colou?r/.test("color")  // true (optional u)
/\d{3}/.test("123")      // true (exactly 3)
/\d{2,4}/.test("12345")  // true (matches "1234")

// Greedy vs Lazy
"<div>text</div>".match(/<.*>/)    // ["<div>text</div>"]
"<div>text</div>".match(/<.*?>/)   // ["<div>"]
💡 Greedy quantifiers match as much as possible
⚡ Add ? after quantifier for lazy (minimal) matching
📌 {n,m} is inclusive - matches n to m times
🟢 Use ? for optional parts like https? for http/https
quantifiersrepetition

Groups & References

Capturing, non-capturing groups, and backreferences

Groups

Grouping patterns and capturing matches

📄 Codejavascript
(x)         Capturing group
(?:x)       Non-capturing group
(?<name>x)  Named capturing group
\1, \2      Backreference to group 1, 2
\k<name>    Backreference to named group

// Examples
const match = "John Smith".match(/(\w+) (\w+)/)
// match[0]: "John Smith" (full match)
// match[1]: "John" (group 1)
// match[2]: "Smith" (group 2)

// Named groups
const regex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
const result = "2024-03-15".match(regex)
// result.groups.year: "2024"
// result.groups.month: "03"
// result.groups.day: "15"

// Non-capturing group (for grouping only)
/(?:https?):\/\//.test("https://")  // true
// Won't create a capture group

// Backreferences
/(\w+) \1/.test("hello hello")      // true (repeated word)
/(['"])(.*?)\1/.test('"text"')      // true (matching quotes)
💡 Use (?:) when you need grouping but not capturing
⚡ Named groups make code more readable and maintainable
📌 Backreferences match the exact same text, not pattern
🟢 Groups are numbered from left to right by opening paren
groupscapturing

Lookarounds

Assertions that don't consume characters

📄 Codejavascript
(?=x)   Positive lookahead
(?!x)   Negative lookahead
(?<=x)  Positive lookbehind
(?<!x)  Negative lookbehind

// Lookahead examples
/\d+(?=px)/.exec("100px")        // ["100"] (number before px)
/\d+(?!px)/.exec("100em")        // ["100"] (number not before px)

// Password validation with lookahead
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/
// Requires: lowercase, uppercase, digit, 8+ chars

// Lookbehind examples
/(?<=\$)\d+/.exec("$100")        // ["100"] (number after $)
/(?<!\$)\d+/.exec("€100")        // ["100"] (number not after $)

// Practical examples
"test@email.com".match(/\w+(?=@)/)      // ["test"]
"$1,234.56".match(/(?<=\$)[\d,]+/)      // ["1,234"]
"not.a.file.txt".match(/\w+(?=\.txt$)/) // ["file"]
💡 Lookarounds are zero-width assertions - don't capture text
⚡ Use multiple lookaheads for complex validation rules
📌 Lookbehind has limited browser support in older versions
🟢 Great for matching based on context without including it
lookaroundassertions

Flags

Regex flags that modify pattern behavior

Pattern Flags

Modifiers that change how patterns work

📄 Codejavascript
g   Global - find all matches
i   Case insensitive
m   Multi-line mode
s   Dot matches newline
u   Unicode mode
y   Sticky mode
d   Has indices (with match indices)

// Using flags
/pattern/gi                       // Multiple flags
new RegExp('pattern', 'gi')       // With constructor

// Global flag (g)
'aaa'.match(/a/)     // ['a'] - first only
'aaa'.match(/a/g)    // ['a','a','a'] - all matches

// Case insensitive (i)
/hello/i.test('HELLO')            // true

// Multi-line (m)
/^line2/m.test('line1\nline2')   // true
/^line2/.test('line1\nline2')    // false

// Dot matches newline (s)
/.+/s.test('line1\nline2')        // matches all including \n
/.+/.test('line1\nline2')         // matches only 'line1'

// Unicode (u)
/\u{1F600}/u.test('😀')          // true (emoji)
/\p{Emoji}/u.test('😀')          // true (Unicode property)

// Sticky (y)
const sticky = /\d+/y
sticky.exec('123 456')   // ['123']
sticky.exec('123 456')   // null (must start at index 3)

// Has indices (d)
const re = /a(b)/d
const match = re.exec('ab')
// match.indices: [[0,2], [1,2]]
💡 Global flag needed for methods like replaceAll and matchAll
⚡ Unicode flag enables \p{} for Unicode properties
📌 Sticky flag matches only at lastIndex position
🟢 Combine flags as needed: /pattern/gim
flagsmodifiers

String Methods

JavaScript methods that work with regex

Testing & Matching

Methods for pattern matching

📄 Codejavascript
// test() - Returns boolean
/\d+/.test("123")                 // true
/[a-z]+/.test("ABC")              // false

// match() - Returns array or null
"hello".match(/[aeiou]/g)         // ['e', 'o']
"hello".match(/(\w)(\w+)/)        // ['hello', 'h', 'ello']

// matchAll() - Returns iterator of all matches
const matches = "cat bat rat".matchAll(/(\w)at/g)
for (const match of matches) {
  console.log(match[0], match[1]) // 'cat' 'c', 'bat' 'b', etc
}

// search() - Returns index or -1
"hello world".search(/world/)     // 6
"hello world".search(/foo/)       // -1

// exec() - Returns match with details
const regex = /(\d{4})-(\d{2})/g
let match
while (match = regex.exec("2024-03-15 2025-04-20")) {
  console.log(match[0])  // "2024-03", "2025-04"
  console.log(match.index) // 0, 11
}
💡 Use test() when you only need true/false
⚡ matchAll() requires global flag and returns iterator
📌 exec() with g flag remembers position via lastIndex
🟢 match() without g returns groups, with g returns all matches
methodstestingmatching

Replacing

Using regex with replace methods

📄 Codejavascript
// replace() - First match only
"hello world".replace(/o/, "0")   // "hell0 world"

// replaceAll() - All matches
"hello world".replace(/o/g, "0")  // "hell0 w0rld"
"hello world".replaceAll(/o/g, "0") // "hell0 w0rld"

// Replacement patterns
"John Smith".replace(/(\w+) (\w+)/, "$2, $1")
// "Smith, John"

// Named groups in replacement
"2024-03-15".replace(
  /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/,
  "$<month>/$<day>/$<year>"
)  // "03/15/2024"

// Function replacer
"hello123world456".replace(/\d+/g, (match) => {
  return match * 2  // Double numbers
})  // "hello246world912"

// Advanced replacer function
"John Smith, Jane Doe".replace(
  /(\w+) (\w+)/g,
  (full, first, last, offset, string) => {
    return \`\${last.toUpperCase()}, \${first[0]}.\`
  }
)  // "SMITH, J., DOE, J."

// Special replacement patterns
$&   Matched substring
$\`  Text before match
$'   Text after match
$$   Literal $
$n   Capture group n
💡 Use function replacer for complex transformations
⚡ $& inserts the entire match in replacement
📌 replaceAll() requires global flag or throws error
🟢 Named groups with $<name> improve readability
replacesubstitution

Splitting

Using regex to split strings

📄 Codejavascript
// Basic split with regex
"a,b;c:d".split(/[,;:]/)          // ['a','b','c','d']

// Split with capture groups (includes separators)
"a1b2c3".split(/(\d)/)
// ['a','1','b','2','c','3','']

// Split with limit
"a-b-c-d".split(/-/, 2)           // ['a','b']

// Split on word boundaries
"HelloWorldTest".split(/(?=[A-Z])/)
// ['Hello','World','Test']

// Split but keep delimiters
"1+2-3*4".split(/(?=[+\-*])|(?<=[+\-*])/)
// ['1','+','2','-','3','*','4']

// Remove empty strings
",,a,,b,c,,".split(/,/).filter(Boolean)
// ['a','b','c']
💡 Capture groups in split() include separators in result
⚡ Use lookahead/behind to split without losing delimiters
📌 filter(Boolean) removes empty strings from result
🟢 Useful for parsing CSV, commands, or structured text
splitparsing

Common Patterns

Frequently used regex patterns

Validation Patterns

Common validation regular expressions

📄 Codejavascript
// Email (basic)
/^[^\s@]+@[^\s@]+\.[^\s@]+$/

// Email (RFC-like)
/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/

// URL
/^(https?:\/\/)?([\w.-]+)\.([a-z]{2,})(\/.*)?$/i

// Phone (US)
/^\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})$/
// Matches: (555) 123-4567, 555.123.4567, 555 123 4567

// Password strength
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/
// Min 8 chars, 1 upper, 1 lower, 1 digit, 1 special

// Credit card
/^(?:\d{4}[-\s]?){3}\d{4}$/
// Matches: 1234-5678-9012-3456 or 1234567890123456

// IPv4 address
/^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/

// Date (YYYY-MM-DD)
/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/

// Time (HH:MM:SS)
/^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)$/

// Hex color
/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i

// Username (alphanumeric + underscore)
/^[a-zA-Z0-9_]{3,16}$/
💡 Email validation should be simple - use service for strict validation
⚡ Use lookaheads for password requirements
📌 Always validate on server side too
🟢 Test patterns with edge cases before using
validationpatterns

Text Processing

Patterns for text manipulation

📄 Codejavascript
// Remove extra spaces
text.replace(/\s+/g, ' ').trim()

// Remove HTML tags
html.replace(/<[^>]*>/g, '')

// Extract URLs from text
text.match(/https?:\/\/[^\s]+/g)

// Convert camelCase to kebab-case
"camelCaseString".replace(/([A-Z])/g, '-$1').toLowerCase()
// "camel-case-string"

// Convert snake_case to camelCase
"snake_case_string".replace(/_([a-z])/g, (_, letter) => letter.toUpperCase())
// "snakeCaseString"

// Find all hashtags
text.match(/#\w+/g)

// Find all mentions
text.match(/@[\w.]+/g)

// Extract numbers with units
"Height: 180cm, Weight: 75kg".match(/\d+(?:cm|kg|m|ft)/g)
// ["180cm", "75kg"]

// Remove duplicate words
text.replace(/\b(\w+)\s+\1\b/gi, '$1')

// Truncate to word boundary
text.substring(0, 100).replace(/\s\w+$/, '...')

// Convert markdown bold to HTML
text.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
💡 Use non-greedy quantifiers for nested patterns
⚡ Remember to escape special characters when needed
📌 Test with edge cases like empty strings
🟢 Chain replace calls for multiple transformations
textprocessing

Data Extraction

Extracting structured data from text

📄 Codejavascript
// Extract all prices
"Items: $10.99, $25.00, €30.50".matchAll(/[\$€£]\d+\.?\d*/g)

// Parse CSV line
function parseCSV(line) {
  return line.match(/(".*?"|[^",\s]+)(?=\s*,|\s*$)/g)
    ?.map(val => val.replace(/^"|"$/g, ''))
}
parseCSV('name,"last, first",age')
// ['name', 'last, first', 'age']

// Extract key-value pairs
"name=John age=30 city=NYC".matchAll(/(\w+)=(\w+)/g)
// Iterate to get: ['name', 'John'], ['age', '30'], etc.

// Parse log entries
const logRegex = /^\[(?<time>[\d:]+)\] \[(?<level>\w+)\] (?<message>.+)$/gm
const logs = logText.matchAll(logRegex)
for (const match of logs) {
  console.log(match.groups)
  // {time: "10:30:45", level: "ERROR", message: "..."}
}

// Extract JSON from text
const jsonRegex = /\{(?:[^{}]|(?:\{[^{}]*\}))*\}/g
text.match(jsonRegex)?.map(json => JSON.parse(json))

// Parse function calls
"func1(arg1, arg2) func2(arg3)".matchAll(/(\w+)\(([^)]*)\)/g)
// Extract function names and arguments

// Extract code blocks from markdown
markdown.matchAll(/\`\`\`(\w+)?\n([\s\S]*?)\`\`\`/g)

// Parse URL components
const url = "https://example.com:8080/path?query=1#hash"
const urlRegex = /^(https?):\/\/([^:\/]+):?(\d+)?(\/[^?#]*)?(\?[^#]*)?(#.*)?$/
const [, protocol, host, port, path, query, hash] = url.match(urlRegex)
💡 Use matchAll() with named groups for structured extraction
⚡ Consider using dedicated parsers for complex formats
📌 Always handle null/undefined from match results
🟢 Named groups make extracted data self-documenting
extractionparsing

Advanced Techniques

Advanced regex patterns and optimization

Performance & Optimization

Writing efficient regular expressions

📄 Codejavascript
// Avoid catastrophic backtracking
// Bad: Nested quantifiers
/(x+x+)+y/.test("xxxxxxxxxxxxxxxxxxxx")  // Very slow!

// Good: Remove the nested quantifier (JS has no atomic
// groups / possessive quantifiers to stop backtracking)
/x+y/.test("xxxxxxxxxxxxxxxxxxxx")         // Fast
// Or emulate an atomic group: lookahead + backreference
/(?=(x+))\1y/.test("xxxxxxxxxxxxxxxxxxxx") // Fast

// Use non-capturing groups when not needed
/(?:https?):\/\//  // Better than /(https?):\/\//

// Anchor patterns when possible
// Slower
/\d{3}-\d{4}/.test(longText)
// Faster
/^\d{3}-\d{4}$/.test(phoneNumber)

// Compile once, use many times
const regex = new RegExp(pattern)  // Once
for (const item of items) {
  regex.test(item)  // Use compiled regex
}

// Be specific with character classes
// Slower
/.+@.+\..+/
// Faster
/[^\s@]+@[^\s@]+\.[^\s@]+/

// Avoid alternation when possible
// Slower
/cat|dog|bird/
// Faster (if applicable)
/(?:cat|dog|bird)/
// Even better (for word list)
new Set(['cat', 'dog', 'bird']).has(word)

// Use lazy quantifiers for better performance
// Can be slow with long strings
/<.*>/
// Often faster
/<.*?>/
💡 Catastrophic backtracking can freeze your app
⚡ Compile regex once when using repeatedly
📌 Be as specific as possible with patterns
🟢 Sometimes a simple string method is faster than regex
performanceoptimization

Dynamic Patterns

Building regex dynamically

📄 Codejavascript
// Build regex from user input
function escapeRegex(string) {
  // Escape special regex characters
  return string.replace(/[.*+?^$'{}()|[\]\\]/g, '\\$&')
}

const userInput = "user.name"
const regex = new RegExp(escapeRegex(userInput))

// Build pattern with variables
const words = ['apple', 'banana', 'orange']
const pattern = new RegExp(`\\b(${words.join('|')})\\b`, 'gi')
// /\b(apple|banana|orange)\b/gi

// Template literal patterns
const year = '2024'
const dateRegex = new RegExp(`${year}-\\d{2}-\\d{2}`)

// Conditional patterns
function buildValidator(options) {
  let pattern = '^'

  if (options.uppercase) pattern += '(?=.*[A-Z])'
  if (options.lowercase) pattern += '(?=.*[a-z])'
  if (options.digit) pattern += '(?=.*\\d)'
  if (options.special) pattern += '(?=.*[@$!%*?&])'

  pattern += `.{${options.minLength},}$`
  return new RegExp(pattern)
}

// Function to create word boundary pattern
function wordBoundary(word) {
  return new RegExp(`\\b${escapeRegex(word)}\\b`, 'gi')
}

// Create pattern from array
function anyOf(items) {
  const escaped = items.map(escapeRegex)
  return new RegExp(`(${escaped.join('|')})`, 'g')
}
💡 Always escape user input to prevent regex injection
⚡ Use template literals for complex pattern building
📌 Remember to double-escape in string literals
🟢 Build reusable pattern factories for common needs
dynamicbuilding

Unicode & Internationalization

Working with Unicode and international text

📄 Codejavascript
// Unicode flag and properties
/\p{Emoji}/u.test('😀')           // true
/\p{Letter}/u.test('א')           // true (Hebrew letter)
/\p{Script=Greek}/u.test('Ω')     // true
/\p{Currency_Symbol}/u.test('€')  // true

// Unicode categories
\p{L}   Letter
\p{N}   Number
\p{P}   Punctuation
\p{S}   Symbol
\p{Z}   Separator

// Match any letter (including non-ASCII)
"Hello世界".match(/\p{L}+/u)      // Matches letters from any language

// Match specific scripts
/\p{Script=Han}+/u                // Chinese characters
/\p{Script=Arabic}+/u              // Arabic script
/\p{Script=Cyrillic}+/u            // Cyrillic script

// Emoji handling
const emojiRegex = /\p{Emoji_Presentation}|\p{Emoji}️/gu
"Hello 👋 World 🌍!".match(emojiRegex)  // ['👋', '🌍']

// Remove diacritics (accents)
const text = "café naïve résumé"
text.normalize("NFD").replace(/\p{Diacritic}/gu, "")
// "cafe naive resume"

// Match words in any language
/\p{L}+/gu.exec("Hello世界مرحبا")
// Matches: "Hello", "世界", "مرحبا"

// Case-insensitive Unicode
/\u{00E9}/ui.test('\u{00C9}')    // true (é matches É)
💡 Always use u flag when working with Unicode
⚡ \p{} properties require Unicode flag
📌 normalize() helps with Unicode comparison
🟢 Test with actual international text samples
unicodeinternational

Debugging & Tools

Tips for debugging and testing regex

Debugging Techniques

Methods for testing and debugging patterns

📄 Codejavascript
// Test step by step
const pattern = /(\d{4})-(\d{2})-(\d{2})/
const input = "2024-03-15"

// 1. Test if it matches
console.log(pattern.test(input))  // true

// 2. Examine the match
const match = input.match(pattern)
console.log(match)
// ['2024-03-15', '2024', '03', '15', index: 0, ...]

// 3. Check all groups
match.forEach((group, i) => {
  console.log(\`Group \${i}: "\${group}"\`)
})

// Debug with verbose patterns
const verboseRegex = new RegExp([
  '(',           // Start group 1
    '\\d{4}',    // Year
  ')',           // End group 1
  '-',           // Literal dash
  '(',           // Start group 2
    '\\d{2}',    // Month
  ')',           // End group 2
].join(''), 'g')

// Test incrementally
const steps = [
  /\d/,          // Single digit
  /\d{4}/,       // Four digits
  /\d{4}-/,      // Four digits and dash
  /\d{4}-\d{2}/, // Add month
  /\d{4}-\d{2}-\d{2}/ // Full pattern
]

steps.forEach((step, i) => {
  console.log(\`Step \${i}: \${step.test(input)}\`)
})

// Log exec progression with global flag
const globalRegex = /\d+/g
let result
while (result = globalRegex.exec("a1b22c333")) {
  console.log({
    match: result[0],
    index: result.index,
    lastIndex: globalRegex.lastIndex
  })
}

// Performance testing
console.time('regex')
for (let i = 0; i < 100000; i++) {
  pattern.test(input)
}
console.timeEnd('regex')

// Create test suite
function testPattern(pattern, tests) {
  tests.forEach(({ input, expected, description }) => {
    const result = pattern.test(input)
    console.log(\`\${result === expected ? '✓' : '✗'} \${description}\`)
    if (result !== expected) {
      console.log(\`  Input: "\${input}"\`)
      console.log(\`  Expected: \${expected}, Got: \${result}\`)
    }
  })
}

// Visual debugging helper
function visualizeMatch(text, pattern) {
  const match = text.match(pattern)
  if (match) {
    const start = match.index
    const end = start + match[0].length
    console.log(text)
    console.log(' '.repeat(start) + '^' + '-'.repeat(match[0].length - 2) + '^')
    console.log(\`Matched: "\${match[0]}" at index \${start}\`)
  }
}

visualizeMatch("hello world", /world/)
// hello world
//       ^----^
// Matched: "world" at index 6
💡 Break complex patterns into smaller testable parts
⚡ Use online tools like regex101.com for visual debugging
📌 Test edge cases: empty strings, special characters
🟢 Create test suites for important patterns
debuggingtesting