JavaScript Regular Expressions
JavaScript regex cheat sheet with pattern syntax, flags, lookaheads, capture groups, common patterns, and practical code examples.
Other JavaScript Sheets
Sign in to mark items as known and track your progress.
Sign inBasic Patterns
Essential regex patterns and metacharacters
Character Classes
Matching specific sets of characters
. 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)Anchors
Matching positions in text
^ 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)Quantifiers
Specifying repetition
* 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>"]Groups & References
Capturing, non-capturing groups, and backreferences
Groups
Grouping patterns and capturing matches
(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)Lookarounds
Assertions that don't consume characters
(?=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"]Flags
Regex flags that modify pattern behavior
Pattern Flags
Modifiers that change how patterns work
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]]String Methods
JavaScript methods that work with regex
Testing & Matching
Methods for pattern matching
// 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
}Replacing
Using regex with replace methods
// 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 nSplitting
Using regex to split strings
// 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']Common Patterns
Frequently used regex patterns
Validation Patterns
Common validation regular expressions
// 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}$/Text Processing
Patterns for text manipulation
// 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>')Data Extraction
Extracting structured data from text
// 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)Advanced Techniques
Advanced regex patterns and optimization
Performance & Optimization
Writing efficient regular expressions
// 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
/<.*?>/Dynamic Patterns
Building regex dynamically
// 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')
}Unicode & Internationalization
Working with Unicode and international text
// 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 É)Debugging & Tools
Tips for debugging and testing regex
Debugging Techniques
Methods for testing and debugging patterns
// 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