Regex tester

Test a regular expression live: see matches and capture groups, preview replacements, and split text — with JavaScript semantics.

Flags
Test text
Results

Enter a pattern and some text to see results

What this tool does

A regular expression is a compact language for describing text patterns, and the only reliable way to write one is to watch it run against real text. This tester does that live, in three modes. Match shows every place the pattern matches, highlighted in your text, with each capture group listed below. Replace previews what String.replace would produce, including $1 and lt;name> references. Split shows how String.split would cut the text apart — including the parts people rarely predict correctly, like captured delimiters appearing in the output.

The pattern runs on your browser's own JavaScript engine, not an imitation of one. Whatever matches here is exactly what will match in your JavaScript code, byte for byte, because it is the same engine doing the work.

Reading the match results

Every match is highlighted in the test text, and listed beneath it with its position — the character offsets where it starts and ends. If the pattern contains capture groups, each group appears under its match with the value it captured. Groups are numbered by their opening parenthesis, left to right, exactly as the engine numbers them for $1, $2 and backreferences; a named group shows its name next to its number. A group that did not take part in the match — say, the losing side of an alternation — is marked as such rather than shown as an empty string, because to your code those are different things: undefined versus "".

A pattern can legitimately match zero characters — ^, \b, or an empty alternative all can. Those zero-length matches highlight nothing, so the tool marks the position with a thin line instead of leaving you wondering where the match went.

The flags

Flags change how the whole pattern behaves, and two of them cause most regex confusion:

  • g (global) — find every match, not just the first. Without it, match shows one result and replace changes one occurrence. This is the flag people forget most often.
  • i (ignore case) — letters match regardless of case.
  • m (multiline) — ^ and $ match at the start and end of every line, not just the whole text.
  • s (dotAll) — the dot matches newline characters too. Without it, . stops at every line break.
  • u (Unicode) — the pattern works in code points, so emoji and other characters outside the basic range behave correctly, and \p{…} property escapes become available.
  • y (sticky) — the match must start exactly where the previous one ended. Useful for tokenizers; surprising everywhere else.
  • d (indices) — the engine records the exact positions of each group. It changes nothing about what matches.

Replacement references

The replacement text is not taken literally — a handful of $ sequences are expanded for each match. $1 through $9 insert what the numbered groups captured, lt;name> inserts a named group, amp; inserts the whole match, and $ produces a literal dollar sign. Everything else is copied as-is.

"2026-07-20".replace(/(?<y>\d{4})-(\d{2})-(\d{2})/, "$3.$2.lt;y>")
// → "20.07.2026"

One JavaScript behavior worth internalising: without the g flag, replace changes only the first occurrence. That is not a quirk of this tool — it is what your code will do. The tool shows a hint when g is off so the single replacement does not read as a bug.

How split really behaves

String.split with a regex has two behaviors that regularly surprise even experienced developers, and the split mode exists largely to make them visible. First, if the pattern contains capture groups, whatever they capture is woven into the output array between the pieces — splitting "a,b" on (,) produces three parts: a, the comma, b. Second, matches at the very start or end of the text, or two adjacent matches, produce empty strings in the output, which the tool shows explicitly rather than hiding.

"a,b".split(/(,)/)   // → ["a", ",", "b"]
",a,".split(/,/)     // → ["", "a", ""]

Runaway patterns are stopped, not endured

Some patterns are traps. A nested quantifier like (a+)+ tried against a long string that almost matches forces the engine to retry exponentially many combinations before giving up — this is called catastrophic backtracking, and it can freeze a browser tab for minutes. This tool runs your pattern in a separate worker thread and stops it after two seconds, so a runaway pattern costs you a message instead of a frozen page. If you hit that message, look for nested quantifiers or overlapping alternatives in the pattern; the fix is usually making the inner repetition and the outer one unable to match the same text.

As with every tool on this site, the pattern and the text never leave your device — the worker is part of the page, not a server.

Frequently asked questions

Which regex flavor does this tester use?
JavaScript (ECMAScript), because the pattern runs on the browser's own engine. Named groups, lookbehind, and \p{…} Unicode property escapes all work as in modern JavaScript. Patterns from PCRE or Python mostly carry over, but constructs JavaScript lacks — possessive quantifiers, atomic groups, \A and \z — will be rejected or mean something else.
Why does my pattern only find one match?
Almost always: the g flag is off. Without it, JavaScript stops at the first match, and replace changes only the first occurrence. Turn on the g checkbox to search the whole text.
What does "did not participate" mean for a group?
The group exists in the pattern but was not used in this particular match — typically because it sits in the branch of an alternation that lost, or under a quantifier that matched zero times. In code its value is undefined, which is different from capturing an empty string, so the tool keeps the two distinct.
Is my pattern or text sent to a server?
No. Matching runs entirely in your browser, inside a worker thread on the same page. The two-second safety timeout is also enforced locally — nothing you type leaves your device.