JavaScript RegExp Methods & Flags Reference
Browse all 8 flags, 8 methods, 40+ syntax tokens, and 12 common patterns — with live examples and an interactive regex tester
Click a flag to expand its description and run the interactive example.
You need a regex that matches dates in YYYY-MM-DD format but only valid ones (not 2024-13-45). You know you need \d{4}-\d{2}-\d{2} as a start, but then you need lookahead for validation, named groups for extraction, and the d flag for match indices. And you can’t remember whether replaceAll() requires the g flag (it does). The regex syntax is compact but dense — 8 flags, 6 methods, 20+ special characters, and recent additions like the v flag for set notation.
Why This Reference (Not the Regex Tester)
PureDevTools has a Regex Tester for testing patterns against strings with highlighted matches. This reference covers all regex syntax — flags (g, i, m, s, u, v, d, y), methods (test, exec, match, matchAll, replace, search, split), character classes, quantifiers, lookahead/lookbehind, named groups, Unicode properties, and common patterns. Use the tester for debugging; use this reference for learning the syntax.
What Are JavaScript Regular Expressions?
A JavaScript regular expression (RegExp) is a pattern used to match character combinations in strings. Every RegExp is described by a pattern and optional flags that modify how matching works.
// Literal syntax
const re1 = /pattern/flags;
// Constructor syntax (useful for dynamic patterns)
const re2 = new RegExp("pattern", "flags");
Regular expressions are used for validation (is this an email?), extraction (pull the date from a log line), replacement (camelCase ↔ kebab-case), and parsing (tokenisers, template engines).
Flags Reference
JavaScript supports eight flags that can be combined freely (except /u and /v which are mutually exclusive).
| Flag | Name | Effect | Since |
|---|---|---|---|
g | Global | Find all matches, not just the first | ES3 |
i | Case-Insensitive | Letters match regardless of case | ES3 |
m | Multiline | ^ and $ match line boundaries | ES3 |
s | Dot-All | . matches \n and other line terminators | ES2018 |
u | Unicode | Full Unicode mode, enables \p{} and \u{XXXX} | ES2015 |
v | Unicode Sets | Superset of u; adds set operations and string properties | ES2024 |
d | Indices | Adds match.indices array with start/end positions per group | ES2022 |
y | Sticky | Matches only at lastIndex — no scanning ahead | ES2015 |
Flags are appended after the closing slash: /pattern/gim. Order does not matter.
String Methods That Accept RegExp
String.prototype.match(regexp)
Without /g, returns the same result as exec() — a single-match array with capture groups, index, and groups. With /g, returns a flat array of all matched substrings.
// First match with groups
const m = "2025-03-15".match(/(\d{4})-(\d{2})-(\d{2})/);
console.log(m[1]); // "2025"
// All matches (no group capture)
"cat bat sat".match(/\w+at/g); // ["cat","bat","sat"]
String.prototype.matchAll(regexp) — ES2020
Returns an iterator of all matches, each with full exec()-style detail. Requires the /g flag.
const re = /(?<word>\w+)=(?<val>\w+)/g;
for (const m of "a=1 b=2".matchAll(re)) {
console.log(m.groups.word, m.groups.val);
}
String.prototype.replace(regexp, replacement)
Replaces the first match (or all with /g). The replacement can be a string with $1, $<name>, $& backreferences, or a function that returns the replacement.
"hello-world".replace(/-(\w)/g, (_, c) => c.toUpperCase()); // "helloWorld"
String.prototype.replaceAll(regexp, replacement) — ES2021
Replaces every match. Requires /g when called with a RegExp.
String.prototype.search(regexp)
Returns the index of the first match, or -1. Always scans from position 0 (ignores /g).
String.prototype.split(regexp, limit?)
Splits the string at each match. Capturing groups are included in the output array.
"one1two2three".split(/(\d)/); // ["one","1","two","2","three"]
RegExp Instance Methods
RegExp.prototype.test(string)
Returns true if the pattern matches anywhere in the string.
/^\d{4}$/.test("2025"); // true
/^\d{4}$/.test("25"); // false
Pitfall: With /g, test() updates lastIndex. Repeated calls on the same instance may return unexpected results.
RegExp.prototype.exec(string)
Returns the first match as an array [fullMatch, group1, group2, ...] with extra properties index, input, groups. Returns null if no match. With /g or /y, advances lastIndex.
const re = /(?<y>\d{4})-(?<m>\d{2})/;
const m = re.exec("Date: 2025-03");
m.groups.y; // "2025"
m.index; // 6
Special Characters Quick Reference
| Token | Name | Matches |
|---|---|---|
. | Wildcard | Any character except \n (or any char with /s) |
^ | Start anchor | Start of string (or line with /m) |
$ | End anchor | End of string (or line with /m) |
\d | Digit | [0-9] |
\D | Non-digit | [^0-9] |
\w | Word char | [A-Za-z0-9_] |
\W | Non-word char | [^A-Za-z0-9_] |
\s | Whitespace | Space, tab, newline, etc. |
\S | Non-whitespace | Any non-whitespace |
\b | Word boundary | Position between \w and \W |
\B | Non-boundary | Position that is NOT a word boundary |
Quantifiers
Quantifiers control how many times the preceding token must appear.
| Quantifier | Meaning | Greedy? |
|---|---|---|
* | 0 or more | ✅ Greedy |
+ | 1 or more | ✅ Greedy |
? | 0 or 1 | ✅ Greedy |
{n} | Exactly n | — |
{n,} | At least n | ✅ Greedy |
{n,m} | Between n and m | ✅ Greedy |
*? | 0 or more | ❌ Lazy |
+? | 1 or more | ❌ Lazy |
{n,m}? | Between n and m | ❌ Lazy |
Greedy vs Lazy: Greedy quantifiers match as many characters as possible; lazy (non-greedy) quantifiers match as few as possible. Append ? to make any quantifier lazy.
Groups and References
Capturing Groups (abc)
Capturing groups record the matched text and expose it via the match array and $1, $2 … in replacement strings.
"2025-03-15".replace(/(\d{4})-(\d{2})-(\d{2})/, "$3/$2/$1");
// "15/03/2025"
Non-Capturing Groups (?:abc)
Group without capturing. Useful for applying a quantifier to a sequence.
/(?:foo)+/.test("foofoo"); // true (no capture overhead)
Named Capturing Groups (?<name>abc) — ES2018
Access captured text by name via match.groups.name or $<name> in replacement strings.
const re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const m = re.exec("2025-03-15");
m.groups.year; // "2025"
m.groups.month; // "03"
m.groups.day; // "15"
Backreferences \1, \k<name>
Match the same text as a previous capture group.
/(["'])[^"']*\1/.test("'hello'"); // true — opening and closing quote match
/(?<q>["'])[^"']*\k<q>/.test('"world"'); // true — named backreference
Alternation |
Matches either the expression on the left or the right.
/cat|dog|bird/.test("I have a bird"); // true
Lookahead and Lookbehind
Lookaround assertions match based on what surrounds the current position without consuming characters.
| Syntax | Type | Matches |
|---|---|---|
(?=abc) | Positive lookahead | Position followed by abc |
(?!abc) | Negative lookahead | Position NOT followed by abc |
(?<=abc) | Positive lookbehind | Position preceded by abc (ES2018) |
(?<!abc) | Negative lookbehind | Position NOT preceded by abc (ES2018) |
// Extract number only when followed by " USD"
/\d+(?= USD)/.exec("100 USD")![0]; // "100"
// Extract amount without the $ sign
/(?<=\$)\d+\.?\d*/.exec("$42.50")![0]; // "42.50"
// Password must contain a digit — without consuming it
/^(?=.*\d).{8,}$/.test("Passw0rd"); // true
Unicode Mode (/u and /v)
Unicode Property Escapes \p{…}
Requires /u or /v. Matches characters that have a specific Unicode property.
/\p{Letter}/u.test("é"); // true — any Unicode letter
/\p{Emoji}/u.test("🚀"); // true — any emoji code point
/\p{Script=Greek}/u.test("α"); // true — Greek script
/\p{Decimal_Number}/u.test("٣"); // true — Arabic-Indic digit
Unicode Sets Mode /v — ES2024
The /v flag is a strict superset of /u and enables:
- Set difference
[A--B]: characters in A but not B - Set intersection
[A&&B]: characters in both A and B - String properties
\p{RGI_Emoji}: multi-code-point sequences like 👨👩👧
// ASCII letters only (difference)
/[\p{Letter}--[^A-Za-z]]/v.test("a"); // true
/[\p{Letter}--[^A-Za-z]]/v.test("é"); // false
// Match full emoji sequences including ZWJ sequences
/\p{RGI_Emoji}/v.test("👨👩👧"); // true
Indices Flag (/d) — ES2022
Adds match.indices: an array of [start, end] tuples for the full match and every capture group. Enables precise source-map and highlighting implementations.
const m = "Hello World".match(/(\w+)\s(\w+)/d);
m.indices[0]; // [0, 11] full match
m.indices[1]; // [0, 5] "Hello"
m.indices[2]; // [6, 11] "World"
// Named groups also get indices
const m2 = "abc".match(/(?<x>b)/d);
m2.indices.groups.x; // [1, 2]
Common Pattern Templates
Email Validation
const EMAIL = /^[\w.+\-]+@[\w\-]+(?:\.[\w\-]+)*\.[a-zA-Z]{2,}$/i;
EMAIL.test("user@example.com"); // true
URL (HTTP/HTTPS)
const URL_RE = /^https?:\/\/(?:www\.)?[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:/~+#]*[\w\-@?^=%&/~+#])?$/i;
URL_RE.test("https://www.example.com/path?q=1"); // true
IPv4 Address
const IPV4 = /^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$/;
IPV4.test("192.168.1.1"); // true
IPV4.test("256.0.0.1"); // false
UUID v4
const UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
UUID_V4.test("550e8400-e29b-41d4-a716-446655440000"); // true
ISO Date (YYYY-MM-DD)
const ISO_DATE = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/;
ISO_DATE.test("2025-03-15"); // true
ISO_DATE.test("2025-13-01"); // false
Strong Password
// At least 8 chars, one uppercase, one lowercase, one digit, one special char
const STRONG_PW = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*]).{8,}$/;
STRONG_PW.test("Passw0rd!"); // true
Performance and Safety Tips
Avoid Catastrophic Backtracking (ReDoS)
Nested quantifiers on overlapping patterns can cause exponential backtracking. Patterns like (a+)+, (\w+)+, or (.*)* can hang the browser with crafted input.
// ❌ Dangerous — nested quantifiers
/^(\w+)+$/.test("aaaaaaaaaaaaaaaaaa!"); // may hang
// ✅ Safe — possessive-style (avoid overlap)
/^\w+$/.test("aaaaaaaaaaaaaaaaaa!"); // fast
Mitigation strategies:
- Prefer atomic groups or possessive quantifiers when available
- Limit input length before running complex patterns
- Use timeout wrappers for user-supplied patterns
Reuse RegExp Instances
Creating new RegExp() on every call allocates a new object. For static patterns, define the literal once outside the function.
// ❌ Allocates a new RegExp on every call
function isEmail(s) { return /^[\w.]+@\w+\.\w+$/.test(s); }
// ✅ Reuse the compiled pattern
const EMAIL_RE = /^[\w.]+@\w+\.\w+$/;
function isEmail(s) { return EMAIL_RE.test(s); }
The lastIndex Trap with /g
A stateful /g RegExp instance updates lastIndex after each exec() or test() call. Reusing the same instance across different strings without resetting can produce incorrect results.
const re = /\d+/g;
re.test("123"); // true — lastIndex = 3
re.test("456"); // false — starts at index 3, finds nothing
re.lastIndex = 0; // reset before reuse
re.test("456"); // true
Browser and Node.js Support
| Feature | Chrome | Firefox | Safari | Edge | Node.js |
|---|---|---|---|---|---|
/s dot-all | 62 | 78 | 11.1 | 79 | 8.5 |
/u Unicode | 50 | 46 | 10 | 15 | 6.0 |
Named groups (?<n>) | 64 | 78 | 11.1 | 79 | 10.0 |
Lookbehind (?<=) | 62 | 78 | 16.4 | 79 | 8.3 |
/d indices | 90 | 88 | 15 | 90 | 16.0 |
/v Unicode sets | 112 | 116 | 17 | 112 | 20.0 |
matchAll() | 73 | 67 | 13 | 79 | 12.0 |
replaceAll() | 85 | 77 | 13.1 | 85 | 15.0 |
Frequently Asked Questions
What is the difference between test() and exec()?
test() returns a boolean and is the fastest option when you only need to know if a match exists. exec() returns a detailed match array (or null) with capture group values, index, input, and groups. Use test() for validation, exec() when you need to extract data from the match.
Why does my global regex test() return alternating true/false?
With the /g flag, test() (and exec()) advance lastIndex after each match. On the next call, the search starts from lastIndex, not the beginning. When lastIndex reaches the end of the string, lastIndex resets to 0 on the next failing call, then the cycle repeats. Fix it by resetting re.lastIndex = 0 before each independent test, or by creating a new RegExp instance per call.
When should I use matchAll() instead of match()?
Use matchAll() when you need both all matches AND their capture groups. match() with /g returns only the matched substrings (no groups). matchAll() returns an iterator where each match includes full exec()-style detail: index, input, groups, and each capture group value.
What is the difference between /u and /v flags?
Both enable Unicode mode, but /v is a strict superset of /u (ES2024). /v adds character class set operations ([A--B] for difference, [A&&B] for intersection), string Unicode properties (\p{RGI_Emoji} matching multi-code-point emoji sequences), and the \q{string} escape inside character classes. They are mutually exclusive — use /v for new code when browser support allows.
How do named capture groups work?
Named groups use the syntax (?<name>pattern). They work like numbered groups but are accessible by name via match.groups.name. In replacement strings, use $<name>. Use \k<name> for named backreferences inside the same pattern. Named groups require at least ES2018 (Chrome 64+, Firefox 78+, Safari 11.1+).
How can I escape user input to use safely in a RegExp?
Characters with special regex meaning (., *, +, ?, (, ), [, ], {, }, ^, $, |, \) must be escaped with a backslash. Use the standard escaping idiom:
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
const safe = new RegExp(escapeRegExp(userInput), "g");
What is the difference between lookahead and lookbehind?
Lookahead ((?=...), (?!...)) asserts what comes after the current position. Lookbehind ((?<=...), (?<!...)) asserts what comes before. Both are zero-width — they do not consume characters. A positive assertion requires the pattern to be present; a negative assertion requires it to be absent. Lookbehind was added in ES2018.