99tools

Regex Tester

runs in your browser

Test a regular expression against your text with live highlighting, a table of every match, and a plain-English reading of what the pattern does.

Try:

Test against

Matches

Write a pattern to begin.

about this tool

Testing as you type

Enter a pattern and some sample text, and matches highlight live with a count. Capture groups are listed for each match, named groups included, so you can see exactly what each part of the pattern caught rather than inferring it from whether the whole thing matched.

The dialect is JavaScript's, so what works here works in the browser and in Node. Most of it transfers to other languages, with the caveats below.

To apply a pattern to text once it works, find & replace uses the same engine and takes $1-style group references in the replacement.

The flags

  • g global — find every match instead of stopping at the first
  • i ignore case
  • m multiline — ^ and $ match at each line rather than only at the start and end of the text
  • s dotAll — . also matches a newline
  • u unicode — treat the pattern as Unicode code points, needed for \p{…} property escapes and for correct handling of characters outside the basic plane
  • y sticky — match only at the current position

m and s are the two whose absence causes the most confusion. If an anchored pattern finds nothing in multi-line text, you want m. If a pattern is meant to span lines and stops at the first newline, you want s.

Catastrophic backtracking

Some patterns are slow in a way that scales terribly. Nested quantifiers over overlapping alternatives — the classic being (a+)+b against a long run of a — force the engine to try an exponential number of paths before giving up. On a server that is a denial-of-service vector, known as ReDoS, and it has taken down real services.

If a pattern is instant on a short string and hangs on a longer one, that is the cause. The fix is usually to make the quantifiers non-overlapping or to anchor the pattern so there are fewer starting positions to try.

Differences from other languages

The pattern is valid JavaScript, and JavaScript is not universal:

  • Lookbehind (?<=…) works here and in modern engines, but not in Safari before 16.4 nor in Python's re with variable length.
  • \d matches only ASCII digits by default in JavaScript, while in some engines it matches any Unicode digit.
  • Atomic groups and possessive quantifiers, which are the clean fix for backtracking in PCRE and Java, do not exist in JavaScript at all.

Everything is local

Pattern and text stay in the page. Regexes are usually written against real sample data — log lines, addresses, customer records — which is exactly what should not be pasted into an unknown site.

Reading the pattern back

Under the pattern is what it actually says, in English, one piece at a time and in the order the engine reads them. A group indents what is inside it, so a nested pattern reads as a nested list rather than a paragraph, and a quantifier is described where it applies rather than being left as a symbol.

It describes rather than judges: a lazy +? is spelled out as "one or more times, as few as possible", the four lookarounds each get their own phrasing, and a backreference says which group it refers to. Where the pattern is broken — a class that is never closed, a backslash at the end — it says so at that point instead of guessing at what was meant.

questions

Why does my pattern with ^ and $ not match anything?
Because without the multiline flag those anchors match only the very start and end of the whole text, not each line. Turn on m to anchor per line.
Why does my pattern stop at the end of the line?
Because the dot does not match a newline by default. Turn on the s flag, dotAll, to let it cross line boundaries — but be careful combining it with a greedy quantifier, which will then swallow the whole document.
Why does my regex hang on longer input?
Catastrophic backtracking. Nested quantifiers over overlapping alternatives, such as (a+)+b, force the engine down an exponential number of paths. On a server this is a denial-of-service vector known as ReDoS; the fix is to make the quantifiers non-overlapping or to anchor the pattern.
Will a pattern that works here work in Python or PHP?
Usually, but not always. This uses JavaScript's engine, where \d matches only ASCII digits, and atomic groups and possessive quantifiers do not exist at all — those being the standard fix for backtracking in PCRE and Java.
Can it explain what a regular expression means?
Yes. Under the pattern is a plain-English reading of it, one piece at a time and in the order the engine reads them, with groups indented so a nested pattern reads as a nested list. Quantifiers are described where they apply, including laziness, and a broken pattern is reported at the point it breaks rather than guessed at.
Is my test data uploaded?
No, the pattern and the text stay in the page. That matters because regexes are usually written against real samples such as log lines, addresses or customer records.