Skip to main content
QUIETLYTIC
Developer

Regex Tester

Test a pattern against sample text with a hard execution timeout.

Local · nothing leaves this browser Waiting for a pattern
Esc Clear
Matches and pattern review

Enter a pattern above.

How it works

Matching runs in a Web Worker with a deadline on it. That is not a performance decision — it is the only way this page can survive a pattern that goes exponential.

Why a timeout needs a separate thread

JavaScript regular-expression matching is synchronous and cannot be interrupted. There is no timeout argument, no abort signal, and no way to ask the engine how far along it is. A pattern such as (a+)+$ tested against a run of as ending in one character that spoils the match forces the engine to try every way of dividing that run between the two quantifiers — a number that doubles with each character added. On the main thread, the tab stops responding and stays that way.

So the work happens on a Worker, the page starts a clock, and if the Worker has not answered in time it is terminated and a fresh one takes its place. The pattern is reported as having exceeded the deadline rather than being left to finish.

The pattern review is advisory

Before running anything, the pattern is scanned for shapes known to backtrack badly: unbounded repetition nested inside unbounded repetition, a repeating group whose branches can match the same text, very large bounded repetition, and backreferences. Each is reported with the reason it matters.

A clean review means none of those shapes are present. It does not mean the pattern is fast — the general question is not one a scanner settles, and a backreference takes the pattern outside the class of expressions that can be matched in linear time at all. The deadline is the guarantee; the review is a warning you get earlier.

Flags behave as they will in your code

Without g, one match is returned, because that is what your own call will do. Capture groups are listed in source order, and a group that did not participate is shown as unset rather than empty — the difference matters when you branch on it.

Example

The second action button loads (a+)+$ against a string built to defeat it. It is there to be run: the deadline fires, the Worker is replaced, and the page stays interactive throughout. That behaviour is the point of the tool, and it is easier to trust having watched it happen than having read that it would.

Frequently asked questions

Why does matching run in a Web Worker?

Because JavaScript regex execution cannot be interrupted. There is no timeout option and no abort signal, so the only way to stop a pattern that has gone exponential is to kill the thread running it — and on the main thread that means killing the tab. The Worker is what makes the deadline possible.

What is catastrophic backtracking?

When a pattern gives the engine many equivalent ways to match the same text, and the input almost matches but ultimately fails, it must try all of them before reporting failure. With unbounded repetition nested inside unbounded repetition, the number of attempts doubles with each character added, so a few dozen characters is enough to hang a process.

The review found nothing. Is my pattern safe?

It means none of the known-bad shapes are present. Deciding whether an arbitrary pattern backtracks badly is not something a scanner settles, and a backreference takes the pattern outside the class that can be matched in linear time at all. Treat a clean review as one check passed, not as a guarantee.

Why do I only get one match without the g flag?

Because that is what your own code will do. A tester that quietly matched everywhere would be showing you behaviour you are not going to get when you paste the pattern into a program.

Is my text sent anywhere?

No. The pattern and the subject text go to a Worker inside your own tab and nowhere else. This page makes no network request while matching, which you can confirm with the devtools network panel open.

Related tools

From the intelligence desk