PureDevTools

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

All processing happens in your browser. No data is sent to any server.

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).

FlagNameEffectSince
gGlobalFind all matches, not just the firstES3
iCase-InsensitiveLetters match regardless of caseES3
mMultiline^ and $ match line boundariesES3
sDot-All. matches \n and other line terminatorsES2018
uUnicodeFull Unicode mode, enables \p{} and \u{XXXX}ES2015
vUnicode SetsSuperset of u; adds set operations and string propertiesES2024
dIndicesAdds match.indices array with start/end positions per groupES2022
yStickyMatches only at lastIndex — no scanning aheadES2015

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

TokenNameMatches
.WildcardAny character except \n (or any char with /s)
^Start anchorStart of string (or line with /m)
$End anchorEnd of string (or line with /m)
\dDigit[0-9]
\DNon-digit[^0-9]
\wWord char[A-Za-z0-9_]
\WNon-word char[^A-Za-z0-9_]
\sWhitespaceSpace, tab, newline, etc.
\SNon-whitespaceAny non-whitespace
\bWord boundaryPosition between \w and \W
\BNon-boundaryPosition that is NOT a word boundary

Quantifiers

Quantifiers control how many times the preceding token must appear.

QuantifierMeaningGreedy?
*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.

SyntaxTypeMatches
(?=abc)Positive lookaheadPosition followed by abc
(?!abc)Negative lookaheadPosition NOT followed by abc
(?<=abc)Positive lookbehindPosition preceded by abc (ES2018)
(?<!abc)Negative lookbehindPosition 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:

// 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:

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

FeatureChromeFirefoxSafariEdgeNode.js
/s dot-all627811.1798.5
/u Unicode504610156.0
Named groups (?<n>)647811.17910.0
Lookbehind (?<=)627816.4798.3
/d indices9088159016.0
/v Unicode sets1121161711220.0
matchAll()7367137912.0
replaceAll()857713.18515.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.

Related Tools

More JavaScript Tools