JavaScript 49 🧬 Regular expressions
const re = /hello/;
console.log(re.test('hello world'));
const re2 = new RegExp('hello');
console.log(re2.test('hello world'));
console.log(/world/.test('hello world'));
console.log(/hello/i.test('HELLO'));
console.log('hello world'.match(/\w+/g));
console.log('2024-01-15'.replace(/(\d{4})-(\d{2})-(\d{2})/, '$3/$2/$1'));
console.log('a,b,c'.split(','));
console.log('abc123'.match(/\d+/)[0]);
console.log([...'abc123def456'.matchAll(/\d+/g)].map(m => m[0]));
const pattern = /(\w+)@(\w+)\.com/;
const result = pattern.exec('contact: alice@example.com');
console.log(result[1], result[2]);
console.log(/^\d{4}-\d{2}-\d{2}$/.test('2024-01-15'));
console.log('phone: 555-1234'.replace(/\d{3}-\d{4}/, '***-****'));
console.log('Hello World'.replace(/\s/g, '_'));
Regular expressions (regex) are patterns for matching text. They look cryptic at first — /^\d{3}-\d{4}$/ — but they’re the most powerful way to search, validate, and transform strings. Every language has them, and JavaScript’s are among the most capable.
Key point: A regular expression is an object that describes a pattern. You can create one with a literal (/pattern/flags) or the RegExp constructor (new RegExp('pattern', 'flags')). Use literals when the pattern is fixed, the constructor when it’s built dynamically.
a – What is a regular expression
A regular expression is a pattern used to match character combinations in strings. It’s a small language inside JavaScript with its own syntax.
Two ways to create a regex:
Literal notation (recommended for static patterns):
const re = /hello/;
Constructor (for dynamic patterns):
const re = new RegExp('hello');
Both are equivalent. Literals are compiled once, are faster, and are easier to read.
The basic methods:
| Method | On | Returns |
|---|---|---|
regex.test(str) | Regex | Boolean |
regex.exec(str) | Regex | Match array or null |
str.match(regex) | String | Match array or null |
str.matchAll(regex) | String | Iterator of matches |
str.replace(regex, repl) | String | New string |
str.replaceAll(regex, repl) | String | New string (all) |
str.search(regex) | String | Index or -1 |
str.split(regex) | String | Array |
Testing with test:
console.log(/hello/.test('hello world'));
// [ true ]
console.log(/hello/.test('goodbye'));
// [ false ]
Returns true or false — the simplest use.
Finding with match:
console.log('hello world'.match(/world/));
// [ [ 'world', index: 6, input: 'hello world', groups: undefined ] ]
The array has the matched text plus index and input.
Global matches:
console.log('a1 b2 c3'.match(/\w\d/g));
// [ [ 'a1', 'b2', 'c3' ] ]
With the g flag, match returns all matches as a plain array.
Replacing with replace:
console.log('hello world'.replace(/world/, 'there'));
// [ 'hello there' ]
Extracting with exec:
const re = /(\d+)/;
const result = re.exec('abc123def');
console.log(result[0]);
// [ '123' ]
console.log(result[1]);
// [ '123' ] ← first capture group
console.log(result.index);
// [ 3 ]
exec gives you the full match info — text, index, input, and captures.
Regex flags:
| Flag | Meaning |
|---|---|
g | Global — find all matches |
i | Case-insensitive |
m | Multiline — ^ and $ match line boundaries |
s | Dotall — . matches newlines too |
u | Unicode — full Unicode support |
y | Sticky — match at lastIndex only |
d | Indices — add indices property |
Examples with flags:
// Case-insensitive
console.log(/hello/i.test('HELLO'));
// [ true ]
// Global — find all
console.log('a a a'.match(/a/g));
// [ [ 'a', 'a', 'a' ] ]
// Multiline
const text = 'line1\nline2\nline3';
console.log(text.match(/^line/gm));
// [ [ 'line', 'line', 'line' ] ]
// Dotall
console.log(/a.b/s.test('a\nb'));
// [ true ]
Why regex matters:
- Validation — emails, URLs, dates, phone numbers
- Extraction — pull data out of text
- Transformation — rename, reformat, sanitize
- Search — find patterns, not just literal strings
- Parsing — tokenize simple grammars
Regex is a language:
┌──────────────────────────────────────────────┐
│ /pattern/flags │
│ │ │
│ │ ┌─────────────────────────────────┐ │
│ │ │ Literal characters: a, b, 1 │ │
│ │ │ Character classes: [a-z], \d │ │
│ │ │ Quantifiers: *, +, ?, {n,m} │ │
│ │ │ Anchors: ^, $, \b │ │
│ │ │ Groups: ( ), (?: ) │ │
│ │ │ Alternation: | │ │
│ │ │ Lookaround: (?= ), (?! ) │ │
│ │ └─────────────────────────────────┘ │
│ │ │
│ └── flags: g, i, m, s, u, y, d │
│ │
└──────────────────────────────────────────────┘
b – Regex syntax
Regex has a compact syntax for describing patterns. This section covers the essentials.
Literal characters:
console.log(/cat/.test('the cat sat'));
// [ true ]
Most characters match themselves literally.
Metacharacters — special meaning:
| Character | Meaning |
|---|---|
. | Any character (except newline by default) |
^ | Start of string (or line with m) |
$ | End of string (or line with m) |
* | 0 or more |
+ | 1 or more |
? | 0 or 1 (or lazy quantifier) |
{n} | Exactly n |
{n,} | n or more |
{n,m} | Between n and m |
[ ] | Character class |
[^ ] | Negated class |
( ) | Group |
(?: ) | Non-capturing group |
| | Alternation (OR) |
\ | Escape |
To match a literal metacharacter, escape it:
console.log(/\./.test('a.b'));
// [ true ]
console.log(/\+/.test('a+b'));
// [ true ]
Character classes:
| Class | Matches |
|---|---|
\d | Digit [0-9] |
\D | Non-digit [^0-9] |
\w | Word char [A-Za-z0-9_] |
\W | Non-word char |
\s | Whitespace [ \t\n\r\f\v] |
\S | Non-whitespace |
. | Any char |
console.log(/\d+/.test('abc123'));
// [ true ]
console.log(/\w+/.test('hello_123'));
// [ true ]
console.log(/\s+/.test('a b'));
// [ true ]
Custom character classes:
console.log(/[abc]/.test('cat'));
// [ true ]
console.log(/[a-z]+/.test('hello'));
// [ true ]
console.log(/[A-Z]/.test('Hello'));
// [ true ]
console.log(/[^0-9]/.test('abc'));
// [ true ]
Ranges: [a-z], [A-Z], [0-9], [a-zA-Z0-9_].
Quantifiers:
| Quantifier | Meaning |
|---|---|
* | 0 or more |
+ | 1 or more |
? | 0 or 1 |
{n} | Exactly n |
{n,} | n or more |
{n,m} | Between n and m |
console.log(/ab*c/.test('ac'));
// [ true ] ← 0 b's
console.log(/ab*c/.test('abc'));
// [ true ]
console.log(/ab*c/.test('abbbc'));
// [ true ]
console.log(/ab+c/.test('ac'));
// [ false ] ← needs at least one b
console.log(/ab?c/.test('ac'));
// [ true ] ← 0 or 1 b
console.log(/a{3}/.test('aaa'));
// [ true ]
console.log(/a{2,4}/.test('aa'));
// [ true ]
Greedy vs lazy quantifiers:
By default, quantifiers are greedy — they match as much as possible.
console.log('<a><b>'.match(/<.+>/)[0]);
// [ '<a><b>' ] ← greedy: matches to last >
Add ? to make them lazy:
console.log('<a><b>'.match(/<.+?>/)[0]);
// [ '<a>' ] ← lazy: matches to first >
Anchors:
| Anchor | Meaning |
|---|---|
^ | Start of string (or line with m) |
$ | End of string (or line with m) |
\b | Word boundary |
\B | Non-word boundary |
console.log(/^hello/.test('hello world'));
// [ true ]
console.log(/world$/.test('hello world'));
// [ true ]
console.log(/\bcat\b/.test('the cat sat'));
// [ true ]
console.log(/\bcat\b/.test('category'));
// [ false ] ← cat isn't a whole word
Groups and captures:
const match = '2024-01-15'.match(/(\d{4})-(\d{2})-(\d{2})/);
console.log(match[1]);
// [ '2024' ]
console.log(match[2]);
// [ '01' ]
console.log(match[3]);
// [ '15' ]
Parentheses capture matches. Access them by index.
Non-capturing groups:
// (?: ) doesn't capture
const match = 'abc123'.match(/(?:abc)(\d+)/);
console.log(match[1]);
// [ '123' ]
Use (?:...) when you need grouping but not the capture.
Named groups:
const match = '2024-01-15'.match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/);
console.log(match.groups.year);
// [ '2024' ]
console.log(match.groups.month);
// [ '01' ]
console.log(match.groups.day);
// [ '15' ]
Named groups make complex patterns readable.
Backreferences:
console.log(/(\w)\1/.test('aa'));
// [ true ]
console.log(/(\w)\1/.test('ab'));
// [ false ]
\1 refers to the first capture group — matches the same text again.
Alternation:
console.log(/cat|dog/.test('I have a dog'));
// [ true ]
console.log(/red|green|blue/.test('yellow'));
// [ false ]
Lookahead and lookbehind:
| Syntax | Meaning |
|---|---|
(?=...) | Positive lookahead |
(?!...) | Negative lookahead |
(?<=...) | Positive lookbehind |
(?<!...) | Negative lookbehind |
// Positive lookahead
console.log('price: $100'.match(/\$(?=\d+)/));
// [ [ '$', index: 7, ... ] ]
// Negative lookahead
console.log('foo bar'.match(/foo(?!bar)/));
// [ null ]
// Positive lookbehind
console.log('$100'.match(/(?<=\$)\d+/)[0]);
// [ '100' ]
// Negative lookbehind
console.log('100 dollars'.match(/(?<!\$)\b\d+\b/)[0]);
// [ '100' ]
Lookarounds assert a condition without consuming characters.
Regex cheat sheet:
| Pattern | Matches |
|---|---|
\d | Digit |
\w | Word char |
\s | Whitespace |
. | Any char |
[abc] | One of a, b, c |
[^abc] | Not a, b, c |
a* | 0+ a |
a+ | 1+ a |
a? | 0 or 1 a |
a{3} | Exactly 3 |
a{2,5} | 2–5 a |
^ | Start |
$ | End |
\b | Word boundary |
( ) | Capture |
(?: ) | Non-capture |
(?<name> ) | Named capture |
| | OR |
(?= ) | Lookahead |
(?! ) | Negative lookahead |
(?<= ) | Lookbehind |
(?<! ) | Negative lookbehind |
c – Regex methods and patterns
This section covers the methods and the patterns you’ll use in real code.
test — quick boolean check:
const emailRe = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
console.log(emailRe.test('alice@example.com'));
// [ true ]
console.log(emailRe.test('not-an-email'));
// [ false ]
Perfect for validation.
exec — full match details:
const re = /(\d{4})-(\d{2})-(\d{2})/;
const match = re.exec('date: 2024-01-15');
console.log(match[0]); // [ '2024-01-15' ]
console.log(match[1]); // [ '2024' ]
console.log(match[2]); // [ '01' ]
console.log(match[3]); // [ '15' ]
console.log(match.index); // [ 6 ]
exec returns null if no match:
const noMatch = /xyz/.exec('hello');
console.log(noMatch);
// [ null ]
Global exec and lastIndex:
const re = /\d+/g;
const str = 'a1 b2 c3';
let m;
while ((m = re.exec(str)) !== null) {
console.log(m[0], m.index);
}
// [ '1' 1 ]
// [ '2' 4 ]
// [ '3' 7 ]
With the g flag, exec remembers lastIndex between calls. Loop until null.
match — simpler alternative:
console.log('a1 b2 c3'.match(/\d+/g));
// [ [ '1', '2', '3' ] ]
matchAll — all matches with details:
const re = /(\w)(\d)/g;
const str = 'a1 b2 c3';
for (const m of str.matchAll(re)) {
console.log(m[1], m[2]);
}
// [ 'a' '1' ]
// [ 'b' '2' ]
// [ 'c' '3' ]
matchAll requires the g flag and returns an iterator.
replace — substitute:
console.log('hello world'.replace(/world/, 'there'));
// [ 'hello there' ]
// Global
console.log('a a a'.replace(/a/g, 'b'));
// [ 'b b b' ]
// With capture groups
console.log('2024-01-15'.replace(/(\d{4})-(\d{2})-(\d{2})/, '$3/$2/$1'));
// [ '15/01/2024' ]
// With a callback
console.log('abc'.replace(/./g, ch => ch.toUpperCase()));
// [ 'ABC' ]
Callback receives match, groups, index:
'2024-01-15'.replace(
/(\d{4})-(\d{2})-(\d{2})/,
(match, y, m, d) => `${d}.${m}.${y}`
);
// [ '15.01.2024' ]
replaceAll — replace all (string or regex with g):
console.log('a a a'.replaceAll('a', 'b'));
// [ 'b b b' ]
console.log('a a a'.replaceAll(/a/g, 'b'));
// [ 'b b b' ]
search — find index:
console.log('hello world'.search(/world/));
// [ 6 ]
console.log('hello world'.search(/xyz/));
// [ -1 ]
Returns index or -1 — ignores the g flag.
split — split by pattern:
console.log('a1b2c3'.split(/\d/));
// [ [ 'a', 'b', 'c', '' ] ]
console.log('one, two;three'.split(/[,;]\s*/));
// [ [ 'one', 'two', 'three' ] ]
Common regex patterns:
Email (simple):
const emailRe = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
URL:
const urlRe = /^https?:\/\/[\w.-]+(?:\.[\w.-]+)+[\w\-._~:/?#[\]@!$&'()*+,;=]*$/;
Date YYYY-MM-DD:
const dateRe = /^\d{4}-\d{2}-\d{2}$/;
Time HH:MM (24h):
const timeRe = /^([01]\d|2[0-3]):[0-5]\d$/;
US Phone:
const phoneRe = /^\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$/;
ZIP code (US):
const zipRe = /^\d{5}(-\d{4})?$/;
Hex color:
const hexRe = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;
IPv4:
const ipv4Re = /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/;
Username (letters, digits, underscore, 3–16 chars):
const userRe = /^[a-zA-Z0-9_]{3,16}$/;
Strong password:
const pwRe = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*]).{8,}$/;
HTML tags (rough):
const tagRe = /<[^>]+>/g;
Whitespace:
const wsRe = /\s+/g;
Word boundary:
const wordRe = /\b\w+\b/g;
Extract numbers:
console.log('abc123def456'.match(/\d+/g));
// [ [ '123', '456' ] ]
Extract emails:
const text = 'Contact: alice@a.com or bob@b.org';
const emails = text.match(/[\w.+-]+@[\w.-]+\.\w+/g);
console.log(emails);
// [ [ 'alice@a.com', 'bob@b.org' ] ]
Clean up whitespace:
console.log(' too much space '.replace(/\s+/g, ' ').trim());
// [ 'too much space' ]
Swap first and last name:
console.log('Smith, John'.replace(/(\w+), (\w+)/, '$2 $1'));
// [ 'John Smith' ]
Format number with commas:
function formatNumber(n) {
return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
console.log(formatNumber(1234567));
// [ '1,234,567' ]
Escape regex special characters:
function escapeRegex(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
console.log(escapeRegex('a.b*c'));
// [ 'a\\.b\\*c' ]
Dynamic regex with constructor:
function containsAny(text, words) {
const pattern = new RegExp(words.map(escapeRegex).join('|'), 'i');
return pattern.test(text);
}
console.log(containsAny('I love JavaScript', ['python', 'javascript']));
// [ true ]
RegExp lastIndex gotcha:
const re = /\d/g;
console.log(re.test('1'));
// [ true ]
console.log(re.lastIndex);
// [ 1 ]
console.log(re.test('1'));
// [ false ] ← starts at index 1, no more digits
console.log(re.lastIndex);
// [ 0 ] ← reset after failed match
With the g flag, test and exec remember where they left off. This is a common bug — either don’t use g with test, or reset lastIndex.
Regex escapes:
| Escape | Meaning |
|---|---|
\d | Digit |
\D | Non-digit |
\w | Word char |
\W | Non-word |
\s | Whitespace |
\S | Non-whitespace |
\b | Word boundary |
\B | Non-boundary |
\n | Newline |
\t | Tab |
\r | Carriage return |
\. | Literal dot |
\* | Literal asterisk |
\\ | Literal backslash |
\uXXXX | Unicode code point |
\xHH | Hex char |
Character class shortcuts:
Inside [ ] | Meaning |
|---|---|
\d | Digit |
\w | Word char |
\s | Whitespace |
. | Literal dot (inside class) |
Inside [ ], . is literal, but \d, \w, \s still work as shortcuts.
Complete Example Session
// ============================================
// PART 1: BASIC TEST
// ============================================
console.log(/hello/.test('hello world'));
// [ true ]
console.log(/hello/.test('goodbye'));
// [ false ]
// ============================================
// PART 2: CONSTRUCTOR
// ============================================
const re = new RegExp('world');
console.log(re.test('hello world'));
// [ true ]
// ============================================
// PART 3: FLAGS
// ============================================
console.log(/hello/i.test('HELLO'));
// [ true ]
console.log('a a a'.match(/a/g));
// [ [ 'a', 'a', 'a' ] ]
// ============================================
// PART 4: MATCH
// ============================================
console.log('hello world'.match(/world/));
// [ [ 'world', index: 6, input: 'hello world', groups: undefined ] ]
console.log('a1 b2 c3'.match(/\w\d/g));
// [ [ 'a1', 'b2', 'c3' ] ]
// ============================================
// PART 5: REPLACE
// ============================================
console.log('hello world'.replace(/world/, 'there'));
// [ 'hello there' ]
console.log('2024-01-15'.replace(/(\d{4})-(\d{2})-(\d{2})/, '$3/$2/$1'));
// [ '15/01/2024' ]
// ============================================
// PART 6: SPLIT
// ============================================
console.log('a,b,c'.split(','));
// [ [ 'a', 'b', 'c' ] ]
console.log('a1b2c3'.split(/\d/));
// [ [ 'a', 'b', 'c', '' ] ]
// ============================================
// PART 7: EXEC
// ============================================
const execRe = /(\d+)/;
const result = execRe.exec('abc123def');
console.log(result[0]);
// [ '123' ]
console.log(result.index);
// [ 3 ]
// ============================================
// PART 8: MATCHALL
// ============================================
const str = 'a1 b2 c3';
const all = [...str.matchAll(/(\w)(\d)/g)];
console.log(all.map(m => m[1]));
// [ [ 'a', 'b', 'c' ] ]
// ============================================
// PART 9: NAMED GROUPS
// ============================================
const named = '2024-01-15'.match(/(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/);
console.log(named.groups.y);
// [ '2024' ]
// ============================================
// PART 10: LOOKAHEAD
// ============================================
console.log(/\d+(?=px)/.test('100px'));
// [ true ]
console.log(/\d+(?=px)/.test('100em'));
// [ false ]
// ============================================
// PART 11: LOOKBEHIND
// ============================================
console.log('$100'.match(/(?<=\$)\d+/)[0]);
// [ '100' ]
// ============================================
// PART 12: BACKREFERENCE
// ============================================
console.log(/(\w)\1/.test('aa'));
// [ true ]
console.log(/(\w)\1/.test('ab'));
// [ false ]
// ============================================
// PART 13: GREEDY VS LAZY
// ============================================
console.log('<a><b>'.match(/<.+>/)[0]);
// [ '<a><b>' ]
console.log('<a><b>'.match(/<.+?>/)[0]);
// [ '<a>' ]
// ============================================
// PART 14: EMAIL VALIDATION
// ============================================
const emailRe = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
console.log(emailRe.test('alice@example.com'));
// [ true ]
console.log(emailRe.test('not-email'));
// [ false ]
// ============================================
// PART 15: EXTRACT NUMBERS
// ============================================
console.log('abc123def456'.match(/\d+/g));
// [ [ '123', '456' ] ]
// ============================================
// PART 16: EXTRACT EMAILS
// ============================================
const text = 'Contact: alice@a.com or bob@b.org';
console.log(text.match(/[\w.+-]+@[\w.-]+\.\w+/g));
// [ [ 'alice@a.com', 'bob@b.org' ] ]
// ============================================
// PART 17: WHITESPACE CLEANUP
// ============================================
console.log(' too much space '.replace(/\s+/g, ' ').trim());
// [ 'too much space' ]
// ============================================
// PART 18: FORMAT NUMBER
// ============================================
function formatNumber(n) {
return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
console.log(formatNumber(1234567));
// [ '1,234,567' ]
// ============================================
// PART 19: ESCAPE REGEX
// ============================================
function escapeRegex(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
console.log(escapeRegex('a.b*c'));
// [ 'a\\.b\\*c' ]
// ============================================
// PART 20: FULL SCRIPT
// ============================================
const re49 = /hello/;
console.log(re49.test('hello world'));
const re2_49 = new RegExp('hello');
console.log(re2_49.test('hello world'));
console.log(/world/.test('hello world'));
console.log(/hello/i.test('HELLO'));
console.log('hello world'.match(/\w+/g));
console.log('2024-01-15'.replace(/(\d{4})-(\d{2})-(\d{2})/, '$3/$2/$1'));
console.log('a,b,c'.split(','));
console.log('abc123'.match(/\d+/)[0]);
console.log([...'abc123def456'.matchAll(/\d+/g)].map(m => m[0]));
const pattern49 = /(\w+)@(\w+)\.com/;
const result49 = pattern49.exec('contact: alice@example.com');
console.log(result49[1], result49[2]);
console.log(/^\d{4}-\d{2}-\d{2}$/.test('2024-01-15'));
console.log('phone: 555-1234'.replace(/\d{3}-\d{4}/, '***-****'));
console.log('Hello World'.replace(/\s/g, '_'));
Quick Reference
Creating Regex
| Form | Example |
|---|---|
| Literal | /pattern/flags |
| Constructor | new RegExp('pattern', 'flags') |
| Dynamic | new RegExp(var, 'g') |
Flags
| Flag | Meaning |
|---|---|
g | Global |
i | Case-insensitive |
m | Multiline |
s | Dotall |
u | Unicode |
y | Sticky |
d | Indices |
String Methods
| Method | Returns |
|---|---|
str.match(re) | Match array or null |
str.matchAll(re) | Iterator of matches |
str.replace(re, s) | New string |
str.replaceAll(re, s) | Replace all |
str.search(re) | Index or -1 |
str.split(re) | Array |
Regex Methods
| Method | Returns |
|---|---|
re.test(str) | Boolean |
re.exec(str) | Match array or null |
Character Classes
| Pattern | Matches |
|---|---|
\d | Digit |
\D | Non-digit |
\w | Word char |
\W | Non-word |
\s | Whitespace |
\S | Non-whitespace |
. | Any (excl. newline) |
[abc] | a, b, or c |
[^abc] | Not a, b, c |
[a-z] | Range |
Quantifiers
| Pattern | Matches |
|---|---|
* | 0+ |
+ | 1+ |
? | 0 or 1 |
{n} | Exactly n |
{n,} | n+ |
{n,m} | n to m |
*? | Lazy 0+ |
+? | Lazy 1+ |
Anchors
| Pattern | Meaning |
|---|---|
^ | Start |
$ | End |
\b | Word boundary |
\B | Non-boundary |
Groups
| Pattern | Meaning |
|---|---|
( ) | Capture |
(?: ) | Non-capture |
(?<name> ) | Named capture |
\1 | Backreference |
Lookarounds
| Pattern | Meaning |
|---|---|
(?= ) | Lookahead |
(?! ) | Negative lookahead |
(?<= ) | Lookbehind |
(?<! ) | Negative lookbehind |
Common Patterns
| Purpose | Pattern |
|---|---|
/^[^\s@]+@[^\s@]+\.[^\s@]+$/ | |
| URL | /^https?:\/\/.+/ |
| Date | /^\d{4}-\d{2}-\d{2}$/ |
| Time | /^([01]\d|2[0-3]):[0-5]\d$/ |
| Phone US | /^\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$/ |
| Hex color | /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/ |
| ZIP | /^\d{5}(-\d{4})?$/ |
| Whitespace | /\s+/g |
| Word | /\b\w+\b/g |
Best Practices
✅ Do This:
// Use literals for static patterns
const re = /hello/i; // ✅
// Use constructor for dynamic patterns
const re = new RegExp(escapeRegex(input), 'g'); // ✅
// Use test for boolean checks
if (/^\d+$/.test(str)) { ... } // ✅
// Use match with /g for all matches
str.match(/\d+/g); // ✅
// Use matchAll for details
for (const m of str.matchAll(/x/g)) { ... } // ✅
// Use named groups for clarity
/(?<year>\d{4})-(?<month>\d{2})/ // ✅
// Escape user input
new RegExp(escapeRegex(userInput)); // ✅
// Reset lastIndex with global regexes
re.lastIndex = 0; // ✅
// Use anchors to avoid partial matches
/^\d{4}$/.test(year); // ✅
❌ Don’t Do This:
// Don't use test with g in a loop
while (re.test(s)) { ... } // ⚠️ infinite loop
// Don't pass user input to RegExp unescaped
new RegExp(userInput); // ❌ regex injection
// Don't write complex regexes without comments
/^(?=.*[a-z])(?=.*[A-Z])...$/; // ⚠️ unreadable
// Don't use regex for HTML parsing
/<div>.*<\/div>/ // ❌ use a parser
// Don't forget anchors
/\d{4}/.test('abc12345'); // ⚠️ matches substring
// Don't use regex for simple string checks
/hello/.test(str); // ⚠️ str.includes('hello')
// Don't confuse match vs matchAll
str.match(/x/g); // ✅ simple list
str.matchAll(/x/g); // ✅ with details
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
g with test in loop | Infinite loop | Reset lastIndex or omit g |
Forgot to escape . | Matches any char | Use \. |
| Greedy quantifier | Matches too much | Use lazy .*? |
| Missing anchors | Partial matches | Add ^ and $ |
| Unescaped user input | Regex injection | Escape special chars |
\d in character class | Still works | Fine — \d OK inside [] |
| Lookbehind support | Old browsers | Check compatibility |
| Dot doesn’t match newline | Multiline strings | Use s flag or [\s\S] |
matchAll without g | Throws | Add g flag |
replace not global | Only first match | Add g flag or use replaceAll |
Real-World Examples
1. Basic Test
console.log(/hello/.test('hello world'));
// [ true ]
2. Case Insensitive
console.log(/hello/i.test('HELLO'));
// [ true ]
3. Global Match
console.log('a a a'.match(/a/g));
// [ [ 'a', 'a', 'a' ] ]
4. Replace
console.log('hello world'.replace(/world/, 'there'));
// [ 'hello there' ]
5. Email Validation
const emailRe = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
console.log(emailRe.test('alice@example.com'));
// [ true ]
6. Date Validation
const dateRe = /^\d{4}-\d{2}-\d{2}$/;
console.log(dateRe.test('2024-01-15'));
// [ true ]
console.log(dateRe.test('01-15-2024'));
// [ false ]
7. Extract Numbers
console.log('abc123def456'.match(/\d+/g));
// [ [ '123', '456' ] ]
8. Extract Emails
const text = 'Contact: alice@a.com or bob@b.org';
console.log(text.match(/[\w.+-]+@[\w.-]+\.\w+/g));
// [ [ 'alice@a.com', 'bob@b.org' ] ]
9. Capture Groups
const match = '2024-01-15'.match(/(\d{4})-(\d{2})-(\d{2})/);
console.log(match[1], match[2], match[3]);
// [ '2024' '01' '15' ]
10. Named Groups
const match = '2024-01-15'.match(/(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/);
console.log(match.groups.y);
// [ '2024' ]
11. Replace with Callback
const result = '2024-01-15'.replace(
/(\d{4})-(\d{2})-(\d{2})/,
(_, y, m, d) => `${d}.${m}.${y}`
);
console.log(result);
// [ '15.01.2024' ]
12. Whitespace Cleanup
console.log(' too much space '.replace(/\s+/g, ' ').trim());
// [ 'too much space' ]
13. Format Number
function formatNumber(n) {
return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
console.log(formatNumber(1234567));
// [ '1,234,567' ]
14. Escape Regex
function escapeRegex(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
console.log(escapeRegex('a.b*c'));
// [ 'a\\.b\\*c' ]
15. Dynamic Regex
function highlight(text, word) {
const re = new RegExp(`(${escapeRegex(word)})`, 'gi');
return text.replace(re, '<mark>$1</mark>');
}
console.log(highlight('hello world', 'world'));
// [ 'hello <mark>world</mark>' ]
16. Password Strength
const pwRe = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/;
console.log(pwRe.test('MyPass123'));
// [ true ]
console.log(pwRe.test('weak'));
// [ false ]
17. Split by Multiple Delimiters
console.log('one, two;three four'.split(/[,;\s]+/));
// [ [ 'one', 'two', 'three', 'four' ] ]
18. Match All Details
const re = /(\w)(\d)/g;
for (const m of 'a1 b2 c3'.matchAll(re)) {
console.log(m[1], m[2], m.index);
}
// [ 'a' '1' 0 ]
// [ 'b' '2' 3 ]
// [ 'c' '3' 6 ]
19. Lookaround
console.log('$100'.match(/(?<=\$)\d+/)[0]);
// [ '100' ]
console.log(/\d+(?=px)/.test('100px'));
// [ true ]
20. Full Script
const re49 = /hello/;
console.log(re49.test('hello world'));
const re2_49 = new RegExp('hello');
console.log(re2_49.test('hello world'));
console.log(/world/.test('hello world'));
console.log(/hello/i.test('HELLO'));
console.log('hello world'.match(/\w+/g));
console.log('2024-01-15'.replace(/(\d{4})-(\d{2})-(\d{2})/, '$3/$2/$1'));
console.log('a,b,c'.split(','));
console.log('abc123'.match(/\d+/)[0]);
console.log([...'abc123def456'.matchAll(/\d+/g)].map(m => m[0]));
const pattern49 = /(\w+)@(\w+)\.com/;
const result49 = pattern49.exec('contact: alice@example.com');
console.log(result49[1], result49[2]);
console.log(/^\d{4}-\d{2}-\d{2}$/.test('2024-01-15'));
console.log('phone: 555-1234'.replace(/\d{3}-\d{4}/, '***-****'));
console.log('Hello World'.replace(/\s/g, '_'));
Visual: Regex Anatomy
┌──────────────────────────────────────────────┐
│ /^(\d{4})-(\d{2})-(\d{2})$/ │
│ │ │ │ │ │ │
│ │ │ │ │ └─── group 3 │
│ │ │ │ └───────── group 2 │
│ │ │ └─────────────── group 1 │
│ │ └─────────────────── anchor start │
│ └───────────────────── anchor end │
│ │
│ Matches: "2024-01-15" │
│ Groups: ['2024', '01', '15'] │
│ │
└──────────────────────────────────────────────┘
Visual: test vs match vs exec
┌──────────────────────────────────────────────┐
│ re.test(str) │
│ → true / false │
│ │
│ str.match(re) │
│ → array of matches │
│ │
│ re.exec(str) │
│ → array with details + groups │
│ │
│ str.matchAll(re) │
│ → iterator of all matches with details │
│ │
└──────────────────────────────────────────────┘
Visual: Greedy vs Lazy
┌──────────────────────────────────────────────┐
│ Input: "<a><b><c>" │
│ │
│ Greedy: /<.+>/ │
│ → "<a><b><c>" (matches to last >) │
│ │
│ Lazy: /<.+?>/ │
│ → "<a>" (matches to first >) │
│ │
│ Add ? to make quantifier lazy │
│ │
└──────────────────────────────────────────────┘
Summary
| Concept | Syntax | Example |
|---|---|---|
| Literal | /pattern/ | /hello/ |
| Constructor | new RegExp('pattern') | Dynamic |
| Flags | /pattern/gi | Global, insensitive |
| Test | re.test(str) | Boolean |
| Exec | re.exec(str) | Match array |
| Match | str.match(re) | Match array |
| Match all | str.matchAll(re) | Iterator |
| Replace | str.replace(re, s) | New string |
| Replace all | str.replaceAll(re, s) | New string |
| Search | str.search(re) | Index |
| Split | str.split(re) | Array |
| Digit | \d | [0-9] |
| Word | \w | [A-Za-z0-9_] |
| Whitespace | \s | [ \t\n\r] |
| Any | . | Any except newline |
| Class | [abc] | a, b, or c |
| Negated | [^abc] | Not a, b, c |
| Quantifier | * + ? {n,m} | Repetition |
| Anchor | ^ $ \b | Position |
| Group | ( ) | Capture |
| Named group | (?<name> ) | Named capture |
| Non-capture | (?: ) | Group without capture |
| Lookahead | (?= ) / (?! ) | Assert ahead |
| Lookbehind | (?<= ) / (?<! ) | Assert behind |
| Alternation | | | OR |
Key takeaways:
- Regex is a pattern language —
test,match,exec,replace,splitare your tools - Use literals (
/pattern/) for static, constructor (new RegExp()) for dynamic - Flags:
g(global),i(case),m(multiline),s(dotall),u(unicode) - Character classes:
\d,\w,\s,.,[abc],[^abc] - Quantifiers:
*,+,?,{n},{n,m}— greedy by default, lazy with? - Anchors:
^and$— always use them for validation - Groups:
( )capture,(?: )doesn’t,(?<name> )names - Lookarounds assert without consuming
- Always escape user input before putting it in a
RegExp - Use named groups for complex patterns — makes them readable
testfor boolean,matchfor arrays,execfor details- Watch out for
lastIndexwith global regexes andtest - Regex isn’t for HTML — use a parser
Remember: Regular expressions are powerful but cryptic. Learn the building blocks — character classes, quantifiers, anchors, groups — and compose them. Use test for validation, match for extraction, replace for transformation. Escape user input. Use named groups for readability. Anchor your patterns. And don’t over-engineer — if a simple includes or split does the job, use it. Master regex, and text manipulation in JavaScript becomes trivial.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!