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.

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');

Methods

MethodReturnsExample
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 gwhile ((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

  • g global — all matches; enables lastIndex.
  • i ignore case. m multiline anchors. s dotAll.
  • u Unicode — code points, \p{…} property escapes, stricter syntax.
  • v unicodeSets (ES2024) — like u plus set operations such as [\p{L}--[a-z]].
  • y sticky — match only at lastIndex; handy for tokenizers.
  • d hasIndices — adds m.indices with 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.