Regular expressions (regex) are one of the most powerful and feared tools in software development. In JavaScript they're natively built in, extremely fast, and once you understand the syntax, they become indispensable.
This guide covers everything you need to know, from the very basics to advanced patterns, with examples you can test right away.
What is a regular expression
A regular expression is a pattern that describes a set of text strings. It's used to search, validate, extract and replace text according to precise rules.
In JavaScript they're created two ways:
// Literal (recommended for fixed patterns)
const re = /pattern/flags;
// Constructor (useful when the pattern comes from a variable)
const re = new RegExp("pattern", "flags");
Core syntax
Special characters
| Symbol | Meaning |
|---|---|
. |
Any character except newline |
\d |
Digit (0-9) |
\w |
Word character (a-z, A-Z, 0-9, _) |
\s |
Whitespace (space, tab, newline) |
\D |
Non-digit |
\W |
Non-word character |
\S |
Non-whitespace |
Quantifiers
| Symbol | Meaning |
|---|---|
* |
0 or more times |
+ |
1 or more times |
? |
0 or 1 time (optional) |
{n} |
Exactly n times |
{n,} |
n or more times |
{n,m} |
Between n and m times |
Anchors
| Symbol | Meaning |
|---|---|
^ |
Start of string (or line with m flag) |
$ |
End of string (or line with m flag) |
\b |
Word boundary |
\B |
Non-word boundary |
Character classes
/[aeiou]/ // any of these vowels
/[a-z]/ // any lowercase letter
/[A-Z]/ // any uppercase letter
/[0-9]/ // any digit (equivalent to \d)
/[^aeiou]/ // any character that is NOT a vowel
/[a-zA-Z0-9]/ // alphanumeric
Flags (modifiers)
Flags are added after the closing /:
| Flag | Meaning |
|---|---|
g |
Global — finds all matches, not just the first |
i |
Case-insensitive — ignores upper/lowercase |
m |
Multiline — ^ and $ match start/end of each line |
s |
Dotall — . also matches newlines |
u |
Unicode — full Unicode character support |
"Hello HELLO hello".match(/hello/gi); // ["Hello", "HELLO", "hello"]
JavaScript methods
test() — Is there a match?
/^\d{5}$/.test("90210"); // true (valid US zip code)
/^\d{5}$/.test("9021X"); // false
match() — Get matches
const text = "Prices: $12, $45 and $99";
// Without g flag: returns first match + groups
text.match(/\$\d+/); // ["$12", index: 9, ...]
// With g flag: returns all matches
text.match(/\$\d+/g); // ["$12", "$45", "$99"]
replace() — Substitute
"hello world".replace(/world/, "JavaScript"); // "hello JavaScript"
"a1b2c3".replace(/\d/g, "X"); // "aXbXcX"
split() — Split by pattern
"one two three".split(/\s+/); // ["one", "two", "three"]
matchAll() — Iterator of all matches with groups
const re = /(\d+)-(\d+)/g;
const text = "2024-01 and 2025-05";
for (const match of text.matchAll(re)) {
console.log(match[1], match[2]); // "2024" "01" → "2025" "05"
}
Capture groups
Parentheses create groups you can extract separately:
const date = "2025-05-04";
const [, year, month, day] = date.match(/(\d{4})-(\d{2})-(\d{2})/);
// year = "2025", month = "05", day = "04"
Named groups
Named groups make code much more readable:
const { groups } = "2025-05-04".match(
/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
);
// groups.year = "2025", groups.month = "05", groups.day = "04"
Non-capturing groups
To group without capturing, use (?:...):
/(?:https?|ftp):\/\//.test("https://example.com"); // true
// (?:https?|ftp) groups the alternative without creating a capture
Lookaheads and lookbehinds
Allow conditional matches without including the context in the result.
// Positive lookahead: number followed by $
"100$ 200€".match(/\d+(?=\$)/g); // ["100"]
// Negative lookahead: number NOT followed by $
"100$ 200€".match(/\d+(?!\$)\b/g); // ["200"]
// Positive lookbehind: number preceded by $
"$100 €200".match(/(?<=\$)\d+/g); // ["100"]
The 10 most useful patterns
// Email (basic)
/^[^\s@]+@[^\s@]+\.[^\s@]+$/
// URL (http/https)
/^https?:\/\/[\w\-]+(\.[\w\-]+)+[^\s]*$/
// US phone number
/^(\+1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$/
// US ZIP code
/^\d{5}(-\d{4})?$/
// Strong password (min 8 chars, 1 uppercase, 1 number, 1 symbol)
/^(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*]).{8,}$/
// Valid JavaScript variable name
/^[a-zA-Z_$][a-zA-Z0-9_$]*$/
// IPv4 address
/^(\d{1,3}\.){3}\d{1,3}$/
// ISO 8601 date
/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?Z?)?$/
// Credit card number (basic, no spaces)
/^\d{13,19}$/
// URL slug (lowercase, hyphens and numbers only)
/^[a-z0-9]+(?:-[a-z0-9]+)*$/
Performance: when NOT to use regex
Regex is a powerful tool but can be expensive with complex patterns that involve backtracking. Avoid them when:
- Parsing HTML or XML — use a DOM parser
- Parsing JSON — use
JSON.parse() - Doing simple string operations —
includes(),startsWith(),endsWith()are faster and more readable
For complex patterns, use a testing tool to verify behavior before deploying to production. Catastrophic backtracking in production is a real denial-of-service vector.
Test it in real time
The best way to learn regex is by experimenting. Our online Regex Tester highlights matches in real time, shows capture groups and includes a quick syntax reference. No installation, directly in the browser.