Regex
Syntax
Literal vs Constructor
// literal — use when pattern is fixed
const re = /hello/i
// constructor — use when pattern is dynamic
const re2 = new RegExp(`^${userInput}$`, 'i')Flags
/pattern/g // global — all matches, not just first
/pattern/i // case insensitive
/pattern/m // multiline — ^ $ match line starts/ends
/pattern/s // dotAll — . matches newlines too
/pattern/gi // combine flagsCharacter Classes
/\d/ // digit [0-9]
/\D/ // not a digit
/\w/ // word char [a-zA-Z0-9_]
/\W/ // not a word char
/\s/ // whitespace (space, tab, newline)
/\S/ // not whitespace
/./ // any char except newlineAnchors & Boundaries
/^start/ // start of string
/end$/ // end of string
/\bword\b/ // word boundary
/\Bword\B/ // not a word boundary
'hello world'.match(/\bworld\b/) // 'world'
'helloworld'.match(/\bworld\b/) // nullQuantifiers
/a*/ // 0 or more
/a+/ // 1 or more
/a?/ // 0 or 1
/a{3}/ // exactly 3
/a{2,5}/ // 2 to 5
/a{2,}/ // 2 or more
/a+?/ // lazy — match as few as possibleGroups & Alternation
/(abc)/ // capturing group
/(?:abc)/ // non-capturing group
/(?<name>x)/ // named group
/cat|dog/ // either cat or dog
/(red|blue) car/ // red car or blue carLookahead / Lookbehind
/\d+(?= dollars)/ // lookahead: digits before " dollars"
/\d+(?! dollars)/ // negative: NOT before " dollars"
/(?<=\$)\d+/ // lookbehind: digits after "$"
/(?<!\$)\d+/ // negative: NOT after "$"Beginner Patterns
Test a Match
// returns true/false — fastest for checking
/\d+/.test('abc123') // true
/^[a-z]+$/.test('Hi') // false (has uppercase)
if (/^\d{5}$/.test(zip)) {
// valid 5-digit zip
}First Match
// returns first match (or null)
'hello 42 world 99'.match(/\d+/)
// ['42', index: 6]
// with /g — returns all matches
'hello 42 world 99'.match(/\d+/g)
// ['42', '99']Replace
// replace first
'hello world'.replace(/world/, 'JS')
// 'hello JS'
// replace all
'aabbcc'.replace(/b/g, 'X')
// 'aaXXcc'
// with capture group
'John Smith'.replace(/(\w+) (\w+)/, '$2, $1')
// 'Smith, John'Split on Pattern
// split on pattern
'one, two, three'.split(/,\s*/)
// ['one', 'two', 'three']
// split on multiple delimiters
'a.b-c_d'.split(/[.\-_]/)
// ['a', 'b', 'c', 'd']Validate Email
const email = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
email.test('a@b.com') // true
email.test('not@real') // falseValidate Hex Color
const hex = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i
hex.test('#fff') // true
hex.test('#1a2b3c') // true
hex.test('#gggggg') // falseIntermediate Patterns
Extract All Matches
const str = 'age: 25, score: 100'
const matches = [...str.matchAll(/(\w+): (\d+)/g)]
matches[0][0] // 'age: 25' (full match)
matches[0][1] // 'age' (group 1)
matches[0][2] // '25' (group 2)Attribute Values
const html = '<img src="cat.png" alt="a cat" width="100">'
const values = [...html.matchAll(/\w+="([^"]*)"/g)]
.map(m => m[1])
// ['cat.png', 'a cat', '100']Tag Contents
const html = '<li>Apple</li><li>Banana</li><li>Cherry</li>'
const items = [...html.matchAll(/<li>(.*?)<\/li>/g)]
.map(m => m[1])
// ['Apple', 'Banana', 'Cherry']All URLs in Text
const text = 'Visit https://a.com and http://b.io/path today'
const urls = text.match(/https?:\/\/[^\s]+/g)
// ['https://a.com', 'http://b.io/path']Key-Value to Object
const config = 'host=localhost;port=5432;db=myapp'
const pairs = [...config.matchAll(/(\w+)=([^;]+)/g)]
.map(m => [m[1], m[2]])
Object.fromEntries(pairs)
// { host: 'localhost', port: '5432', db: 'myapp' }Strip & Collapse
// strip HTML tags
'<p>Hello <b>world</b></p>'.replace(/<[^>]*>/g, '')
// 'Hello world'
// collapse whitespace
'hello world'.replace(/\s+/g, ' ')
// 'hello world'Advanced Patterns
Named Groups to Object
const str = 'name: Alice, age: 30, role: admin'
const entries = [...str.matchAll(/(?<key>\w+): (?<val>\w+)/g)]
.map(m => [m.groups.key, m.groups.val])
Object.fromEntries(entries)
// { name: 'Alice', age: '30', role: 'admin' }Markdown Links
const md = 'See [Google](https://google.com) and [MDN](https://mdn.io)'
const links = [...md.matchAll(/\[([^\]]+)\]\(([^)]+)\)/g)]
.map(m => ({ text: m[1], url: m[2] }))
// [{ text: 'Google', url: 'https://google.com' },
// { text: 'MDN', url: 'https://mdn.io' }]Slugify
function slugify(str) {
return str
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-|-$/g, '')
}
slugify('Hello World!') // 'hello-world'camelCase to kebab
function toKebab(str) {
return str.replace(/([a-z])([A-Z])/g, '$1-$2')
.toLowerCase()
}
toKebab('backgroundColor') // 'background-color'
toKebab('fontSize') // 'font-size'Password Strength
const strong = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%]).{8,}$/
// requires: lowercase, uppercase, digit,
// special char, min 8 chars
strong.test('Passw0rd!') // true
strong.test('password') // falseCSV Line Parse
const line = 'Alice,"New York, NY",30'
const fields = [...line.matchAll(/("(?:[^"\\]|\\.)*"|[^,]*)/g)]
.map(m => m[1].replace(/^"|"$/g, ''))
// ['Alice', 'New York, NY', '30']Last updated on