Skip to content

Regex tester and debugger

Test JavaScript regular expressions live with highlighted matches, capture and named group tables, a replace preview, flags, and a built-in cheatsheet.

  • Runs in your browser
  • Nothing you enter is sent
  • Free, no account
Pattern
Written the way you would pass it to new RegExp() — no surrounding slashes needed.
Flags
Test string
Matches are highlighted live. Everything runs inside a background worker in your own browser.
0 matches
Highlighted result
Regular expressions are compact, powerful, and occasionally infuriating.
Test them here before shipping them into production code.
Cheatsheet
The syntax you look up most often, in one place.

How to test a regular expression

  1. Type the pattern without surrounding slashes — it is passed straight to new RegExp().
  2. Tick the flags you need. g is on by default, because without it only the first match is found.
  3. Paste the text to match against. Matches are highlighted as you type, alternating colours so adjacent matches stay distinguishable.
  4. Read the match table for exact positions and every captured group, numbered and named.
  5. Turn on the replace preview to see the result of String.replace with your replacement string.

Which flavour is this?

The JavaScript (ECMAScript) engine built into your own browser. That means the behaviour you see here is exactly the behaviour your front-end code, your Node service and your JSON schema validator will show — including the parts JavaScript does differently from PCRE. Notably, JavaScript has no atomic groups, no possessive quantifiers, no recursion, no \A or \z anchors, and lookbehind is variable-length (which most other engines do not allow).

Catastrophic backtracking, and why this page cannot freeze

A regular expression engine that hits a dead end backtracks and tries another path. With nested quantifiers such as (a+)+$, the number of paths grows exponentially with the length of the input: 25 characters of a followed by a ! can take longer than the age of the universe. This is the mechanism behind ReDoS, a real denial-of-service class that has taken down production services.

A running regular expression cannot be interrupted on the main thread, so this tool evaluates every pattern inside a Web Worker with a two-second budget. If the budget expires the worker is terminated and you get an explanation instead of a locked-up tab. That is also a useful signal in itself: if a pattern trips the guard here, do not ship it anywhere user input can reach.

How to fix a backtracking pattern

  • Make sure two parts of the pattern cannot match the same text. (\s*\w+)* is ambiguous; [\s\w]* is not.
  • Replace .* between delimiters with a negated class: "[^"]*" instead of ".*".
  • Anchor the pattern with ^ and $ so the engine cannot retry from every position.
  • For deeply structured input, stop using a regular expression and write a parser.

Flags at a glance

FlagNameEffect
gglobalKeep searching after the first match; required for replace-all and for the match list
iignoreCaseCase-insensitive matching
mmultiline^ and $ match at each line break rather than only at the ends of the string
sdotAll. also matches newlines
uunicodeTreat the pattern as code points; required for \p{…} property escapes and correct handling of astral characters
ystickyMatch only at lastIndex; useful for tokenisers, and it will find far fewer matches than g

Named capture groups

Write (?<year>\d{4}) and the match table gains a column for year. In your code you read it as match.groups.year, and in a replacement string as $<year>. Named groups make a pattern survive editing: adding a group in the middle renumbers everything after it, but names do not move.

A note on parsing HTML and email

The preset patterns here are pragmatic, not exhaustive. The full grammar for an email address (RFC 5322) permits quoted strings, comments and nested parentheses, and the "correct" regular expression for it runs to several thousand characters while still not proving the address exists. Match loosely, then verify by sending mail. Likewise, HTML is not a regular language — a tag matcher is fine for a quick grep over a log file, and wrong for anything that must be correct.

Your test data stays here

Patterns and subject text are evaluated by your browser's own engine inside a worker. Nothing is transmitted, so production log samples, customer records and unreleased content are safe to paste.

Questions

Which regex flavour does this use?

The JavaScript (ECMAScript) engine built into your browser, so behaviour matches exactly what your front-end or Node code will do. PCRE-only constructs such as atomic groups or recursion are not supported.

What happens if my pattern hangs the browser?

Nested quantifiers can cause catastrophic backtracking. Matching runs under a time budget and a match-count cap; if the budget is exceeded the run is abandoned and you get a warning naming the likely cause instead of a frozen tab.

How do I use named capture groups?

Write (?<name>…) in the pattern and reference it as $<name> in the replacement. Named groups get their own column in the match table alongside the numbered ones.

What does the y (sticky) flag do?

It anchors each attempt at lastIndex, so matching only succeeds if it starts exactly where the previous match ended. It is useful for hand-written tokenisers and will produce far fewer matches than g on the same pattern.

Is my test data sent anywhere?

No. The pattern and the subject text are evaluated by your own browser RegExp engine. Nothing is logged or transmitted, so production log samples are safe to paste.