Regex in JavaScript: From Beginner to Advanced Patterns
Regular expressions (regex) are one of the most powerful - and most feared - tools in a developer's arsenal. They can validate email addresses, parse log files, extract data from strings, and replace complex text patterns in a single line of code.
This guide takes you from zero to confident regex usage in JavaScript, covering basic syntax, quantifiers, groups, lookahead/lookbehind, and practical patterns you will use every day.
Regex Basics in JavaScript
In JavaScript, you create regex patterns in two ways:
// Literal syntax
const pattern = /hello/gi;
// Constructor syntax
const pattern = new RegExp('hello', 'gi');
Essential Flags
| Flag | Meaning |
|---|---|
g | Global - find all matches, not just the first |
i | Case-insensitive matching |
m | Multiline - ^ and $ match line boundaries |
s | Dotall - . matches newlines |
u | Unicode - enable Unicode property escapes |
Character Classes
Character classes match specific sets of characters:
\d // Any digit [0-9]
\w // Any word character [a-zA-Z0-9_]
\s // Any whitespace (space, tab, newline)
\D // NOT a digit
\W // NOT a word character
. // Any character (except newline by default)
Custom Character Classes
Use brackets to define custom sets:
[aeiou] // Any vowel
[A-Z] // Any uppercase letter
[0-9a-f] // Any hex character
[^0-9] // NOT a digit (negated class)
Quantifiers
Quantifiers control how many times a pattern repeats:
* // 0 or more
+ // 1 or more
? // 0 or 1
{3} // Exactly 3
{2,5} // Between 2 and 5
{3,} // 3 or more
Greedy vs Lazy Matching
By default, quantifiers are greedy - they match as much as possible. Add ? to make them lazy:
const html = '<div>Hello</div><div>World</div>';
// Greedy: matches everything between first < and last >
html.match(/<.+>/); // '<div>Hello</div><div>World</div>'
// Lazy: matches the smallest possible string
html.match(/<.+?>/); // '<div>'
This is one of the most common sources of regex bugs. Always use lazy quantifiers when extracting content between delimiters.
Capturing Groups
Parentheses create capturing groups that extract specific parts of a match:
const datePattern = /(\d{4})-(\d{2})-(\d{2})/;
const match = '2026-03-02'.match(datePattern);
console.log(match[1]); // '2026' (year)
console.log(match[2]); // '03' (month)
console.log(match[3]); // '02' (day)
Named Capturing Groups
For readability, use named groups:
const pattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2026-03-02'.match(pattern);
console.log(match.groups.year); // '2026'
console.log(match.groups.month); // '03'
Non-Capturing Groups
When you need grouping for logic but do not need the capture, use (?:...):
/(?:https?|ftp):\/\// // Groups http/https/ftp but doesn't capture
Lookahead and Lookbehind
These are zero-width assertions - they check for a pattern without including it in the match.
Positive Lookahead (?=...)
Match something only if it is followed by a specific pattern:
// Match a number only if followed by "px"
const pattern = /\d+(?=px)/g;
'12px 8em 16px'.match(pattern); // ['12', '16']
Negative Lookahead (?!...)
Match something only if it is NOT followed by a specific pattern:
// Match numbers NOT followed by "px"
const pattern = /\d+(?!px)/g;
'12px 8em 16px'.match(pattern); // ['1', '8', '1']
Positive Lookbehind (?<=...)
Match something only if preceded by a specific pattern:
// Match amount after dollar sign
const pattern = /(?<=\$)\d+/g;
'$100 and €200'.match(pattern); // ['100']
Negative Lookbehind (?<!...)
Match something only if NOT preceded by a specific pattern:
// Match numbers not preceded by $
const pattern = /(?<!\$)\d+/g;
'$100 and 200'.match(pattern); // ['00', '200']
Practical Patterns You Will Use
Email Validation
const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
URL Extraction
const urlPattern = /https?:\/\/[^\s<>"{}|\\^`\[\]]+/g;
Password Strength
// At least 8 chars, 1 uppercase, 1 lowercase, 1 digit, 1 special
const strongPassword = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
Phone Number (International)
const phonePattern = /^\+?[1-9]\d{1,14}$/;
IP Address (v4)
const ipv4Pattern = /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/;
Common Mistakes to Avoid
-
Catastrophic backtracking - Avoid nested quantifiers like
(a+)+. They cause exponential time complexity on non-matching inputs. -
Forgetting to escape special characters - Characters like
.,*,+,?,(,),[,],{,},\,^,$,|have special meaning and must be escaped with\. -
Not anchoring validation patterns - Without
^and$, your pattern does a partial match."admin".match(/admin/)also matches "superadmin". -
Using regex for HTML parsing - Regex cannot handle nested structures. Use a DOM parser instead.
Testing Your Regex Patterns
Always test regex patterns against edge cases before deploying to production. Use our free Regex Tester to visualise matches, test against sample strings, and debug your patterns in real time - entirely in your browser.
Performance Tips
- Be specific -
/[0-9]/is faster than/\d/in some engines because it avoids Unicode digit matching - Avoid backtracking - Use atomic groups or possessive quantifiers when available
- Pre-compile patterns - If using the same regex in a loop, define it outside the loop
- Use
test()for boolean checks -regex.test(string)is faster thanstring.match(regex)when you only need true/false
Frequently Asked Questions
What is the difference between test() and match() in JavaScript?
test() returns a boolean (true/false). match() returns the match result array or null. Use test() for validation, match() for extraction.
Can regex match across multiple lines?
Yes, use the m (multiline) flag to make ^ and $ match line boundaries, and the s (dotall) flag to make . match newlines.
How do I make regex case-insensitive?
Add the i flag: /pattern/i or new RegExp('pattern', 'i').
Found this helpful?
Join thousands of developers using our tools to write better code, faster.