Regex Tester & Explainer
Paste a pattern to see it matched live, broken down into plain English piece by piece, and checked for the pattern shapes known to freeze a page — all using your browser's own regex engine, not a reimplementation of it.
{{ parseError }}
This pattern may hang on certain input (catastrophic backtracking). {{ redosWarnings[0].message }} ({{ redosWarnings.length - 1 }} more issue{{ redosWarnings.length > 2 ? 's' : '' }} found.)
Matching is paused because this pattern may hang the page — see the warning above.
{{ matches.length }} match{{ matches.length === 1 ? '' : 'es' }}
| # | Match | Index | Length | Groups |
|---|---|---|---|---|
| {{ i + 1 }} | {{ m.match }} |
{{ m.index }} | {{ m.match.length }} |
—
{{ g.name ? g.name : g.number }}: {{ g.value === null ? '(no match)' : g.value }}
|
Paste a test string above to see matches highlighted live.
- {{ line.text }}
Supports $1, $<name>, $$,
$&, $` and $' — the same substitution patterns
.replace() itself understands, because this preview runs the real thing.
Replace preview is paused because this pattern may hang the page — see the warning above.
Before
{{ testText }}
After
{{ replacedText }}
Testing is paused because this pattern may hang the page — see the warning above.
-
{{ r.line || '(empty line)' }}matched: "{{ r.match }}"
{{ listResults.filter(r => r.matched).length }} of {{ listResults.length }} lines matched
Type a pattern above to test it, see it explained, or preview a replace.
-
{{ row.description }}
{{ row.example }} - No reference entries match "{{ refQuery }}".
Your pattern and test string are parsed and matched entirely in your browser, using its own native regular expression engine. Neither is ever uploaded to a server.
What actually does the matching
Every match, replace and test on this page runs through your browser's own native regular expression
engine — the same one RegExp, .match() and .replace() use in
real code. This tool never reimplements matching itself; what it builds from scratch is a parser that
reads the pattern's text and turns it into the plain-English breakdown, the Quick Reference
panel, and the backtracking-risk warning — all of that runs before your pattern ever touches a single
character of your test string.
This explains and tests JavaScript (ECMAScript) regular expressions specifically —
the dialect used in a browser or Node. PCRE (PHP, most command-line grep), Python's re
and others differ in real ways; a pattern copied from a different language's documentation may parse
here but behave differently there.
Why matching sometimes pauses with a warning instead of running
A small number of pattern shapes — most famously something like (a+)+ — can make the
regex engine try an exponentially growing number of ways to fail a match, freezing the page on input
that looks perfectly ordinary. This tool scans your pattern's structure for those shapes before
running anything, and if it finds one, live matching pauses until you explicitly confirm you want to
run it anyway — a warning you have to scroll past doesn't stop a frozen tab; not running the pattern
until you say so does.
Frequently asked questions
Does this reimplement regular expression matching?
No. Every match, test and replace runs through your browser's own native RegExp — the exact engine your own code would use. What this tool builds itself is a parser that reads the pattern's text to produce the plain-English explanation, the Quick Reference panel and the backtracking-risk check; none of that touches how matching actually happens.
Which regex dialect does this explain?
JavaScript (ECMAScript) regular expressions — the dialect RegExp, .match() and .replace() use in a browser or Node. PCRE (PHP, most command-line grep), Python's re and others differ in real ways, such as possessive quantifiers and some lookbehind history. A pattern copied from a different language's docs may parse here but behave differently there.
Why did matching pause with a warning instead of just running?
The pattern contains a shape known to cause catastrophic backtracking — most famously something like (a+)+ — where the engine can try an exponentially growing number of ways to fail a match on ordinary-looking input, freezing the page. A warning you could scroll past wouldn't stop a frozen tab, so matching stays paused until you explicitly confirm you want to run it anyway.
What is a lookahead or lookbehind, and why doesn't it show up in my match?
Both are zero-width: they check that something does or doesn't come next (or immediately before), but that checked part is never consumed into the match itself or into any capture group. This is the single most common source of "why isn't this group showing up" confusion, which is why the explainer labels every lookaround zero-width explicitly.
Is my pattern or test string sent anywhere?
No. Parsing, matching, the explanation and the replace preview all run entirely in your browser with JavaScript. Nothing is transmitted to a server.