Regex Tester

Regular expressions are written once and debugged repeatedly, usually against inputs nobody anticipated. Testing against real sample text before deploying is the difference between a pattern that works and one that works on the three examples you had in mind.

How to use it

  1. Enter a pattern, without the enclosing slashes.
  2. Set the flags you need.
  3. Paste sample text and review the matches and capture groups.

The flags

Six flags matter in JavaScript, and two of them behave in ways that regularly cause bugs.

The lastIndex trap

A regex with the g or y flag carries mutable state. Each call to test or exec starts from the lastIndex property and updates it, so calling test twice on the same string with the same regex object returns true and then false.

This bites hardest when a regex is defined at module scope and reused, which is otherwise good practice. The symptom is a validation function that rejects every second identical input, and it is genuinely difficult to spot in review because the code looks correct.

Fixes: do not use g on a regex you are calling test with, reset lastIndex to zero before each use, or construct the regex fresh each time. The first is usually right, because test does not need g.

Greedy, lazy, and catastrophic backtracking

Quantifiers are greedy by default: they consume as much as possible, then give characters back until the rest of the pattern matches. Adding a question mark makes them lazy, consuming as little as possible and expanding only as needed.

The classic demonstration is matching an HTML tag. The pattern <.+> against <a><b> matches the whole string, because the greedy quantifier takes everything and then backtracks only enough to find the final angle bracket. The lazy form <.+?> matches just <a>.

Backtracking becomes dangerous when quantifiers nest. A pattern like (a+)+b against a long run of a characters with no b forces the engine to try every possible way of partitioning those characters between the inner and outer quantifiers, which is exponential in the input length. Twenty-five characters can take seconds; thirty can hang the thread.

This is ReDoS, and it is a real availability vulnerability rather than a curiosity, because JavaScript regex evaluation is synchronous and blocks the event loop. If you are writing a pattern that will run against user-supplied input, avoid nested quantifiers over overlapping character classes, and test with a long non-matching string specifically to see whether it returns promptly.

Capture groups, and when not to use a regex at all

Parentheses capture by default, which allocates and stores the matched substring. Prefixing with ?: makes a group non-capturing, which is what you want when the parentheses are only there for grouping. Named groups, written ?<name>, are considerably more readable than positional indices in any pattern with more than two captures.

Lookahead, written ?= and ?!, and lookbehind, written ?<= and ?<!, assert without consuming. Lookbehind is supported in all current browsers but was late to arrive, and variable-length lookbehind remains unsupported in some other regex flavours.

The final point is knowing when to stop. Regular expressions cannot parse nested structures, because matching arbitrarily nested brackets requires counting and regular languages cannot count. HTML, JSON, and source code all fall into this category. A regex that appears to work on your sample will fail on nesting, attributes in an unexpected order, or a comment containing something that looks like markup. Use a parser.

At a glance

FlavourJavaScript, ECMAScript regular expressions
Flagsg, i, m, s, u, y
ShowsMatch indices and capture groups
TransmittedNothing

Frequently asked questions

Why does my regex match too much?

Quantifiers are greedy and consume as much as they can before backtracking. Add a question mark to make them lazy, or replace the dot with a negated character class that cannot cross the boundary.

Why does test return false every second call?

The g flag makes the regex stateful via lastIndex. Drop g when using test, reset lastIndex, or build the regex fresh each time.

What is catastrophic backtracking?

Nested quantifiers over overlapping patterns can force the engine through exponentially many combinations. On user-supplied input that is a denial-of-service vector, because JavaScript regex evaluation blocks the event loop.

Can I parse HTML with a regex?

No. Nested structures require counting, which regular languages cannot do. Use DOMParser for HTML and a real parser for JSON and code.

Read more

Working with text — Diffs cannot see movement, regular expressions cannot count, and case conversion is not locale-independent.

Related tools