const text = 'Order #1042 shipped 2026-09-27, order #1043 pending';
// All order numbers with positions
for (const m of text.matchAll(/#(\d+)/g)) console.log(m.index, m[1]);
// Named groups
const { year, month } = text.match(/(?<year>\d{4})-(?<month>\d{2})/).groups;
// Replace with a function
text.replace(/#(\d+)/g, (_, n) => `#${Number(n) + 1}`);
// Build from user input safely
const escape = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const re = new RegExp(escape(query), 'gi');JavaScript regex
How regular expressions work in JavaScript and Node.js: creating them, the methods that use them, every flag, and the lastIndex trap that catches everyone once.
Methods
| Method | Returns | Example |
|---|---|---|
re.test(str) | true / false | /^\d+$/.test("42") |
str.match(re) | First match with groups (no g) or all strings (g) | "a1b22".match(/\d+/g) → ["1","22"] |
str.matchAll(re) | Iterator of match objects (needs g) | [..."a1b22".matchAll(/\d+/g)] |
re.exec(str) | One match object; advances lastIndex with g | while ((m = re.exec(s))) {…} |
str.replace(re, x) | Replace first (or all with g) | s.replace(/\s+/g, " ") |
str.replaceAll(re, x) | Replace all (re must have g) | s.replaceAll(/-/g, "_") |
str.search(re) | Index of first match or -1 | "abc1".search(/\d/) → 3 |
str.split(re) | Split; captured groups are included | "a, b;c".split(/[,;]\s*/) |
Flags
gglobal — all matches; enableslastIndex.iignore case.mmultiline anchors.sdotAll.uUnicode — code points,\p{…}property escapes, stricter syntax.vunicodeSets (ES2024) — likeuplus set operations such as[\p{L}--[a-z]].ysticky — match only atlastIndex; handy for tokenizers.dhasIndices — addsm.indiceswith start/end of every group.
The lastIndex trap
A regex with g or y is stateful. const re = /a/g; re.test('a'); re.test('a'); returns true then false, because the second call starts at index 1. Don't reuse a global regex for test() across different strings.
Replacement patterns
In the replacement string, $1 is group 1, $<name> a named group, $& the whole match and $$ a literal dollar. Pass a function instead of a string when the replacement needs logic; it receives the match, each group, the offset and the whole string.
Unicode
Without u, . matches half of an emoji (one UTF-16 code unit). With u, it matches the whole code point, and \p{L}, \p{Emoji} or \p{Script=Greek} become available.
Everything on this page runs as-is in the regex tester, which uses your browser's own JavaScript engine.
Questions
Should I use a regex literal or new RegExp()?
Use a literal (/\d+/g) when the pattern is fixed — it is parsed once and needs no extra escaping. Use new RegExp(string, flags) when you build the pattern at runtime; remember to double backslashes inside the string ("\\d+").
Why does my global regex alternate between true and false?
A regex with the g or y flag keeps a lastIndex. Calling re.test() repeatedly on different strings continues from the previous position. Drop the g flag for test(), or reset re.lastIndex = 0.
What is the difference between match and matchAll?
str.match(/x/g) returns an array of matched strings with no groups or positions. str.matchAll(/x/g) returns an iterator of full match objects, each with index and groups. matchAll requires the g flag.
Does JavaScript support lookbehind?
Yes, since ES2018 — in all current browsers and Node.js 10+. Unlike Python, the lookbehind can be variable-width.