Regex Tester & Debugger
Write a regular expression and watch it match, capture and replace live against your own text — all in your browser, nothing uploaded.
Click one to load its pattern — it replaces the box above so you can tweak it.
| Group | Value | Start |
|---|
Runs entirely in your browser — nothing you type is uploaded. The pattern is compiled with JavaScript's own RegExp engine on your device; there are no network requests and no analytics on this tool.
What this regex tester does
A regular expression is a compact pattern for finding and shaping text. Type one in the box above and this page compiles it with the browser's native RegExp engine and re-runs it against your test string on every keystroke — no "Run" button. Every match is highlighted, a table breaks each match into its capture groups with their exact start offsets, and an optional replacement is previewed live so you see precisely what String.prototype.replace would produce.
A worked example, captures and all
The pattern loaded above is /(\w+)@(\w+\.\w+)/g and the test text begins:
Contact ada@example.com or grace@polyatic.com for details.
With the g flag the engine scans left to right and finds two matches. The first is ada@example.com, starting at offset 8. Its two groups come from the two parenthesised parts: group 1 (before the @) captures ada, group 2 (after it) captures example.com. Group 0, always the whole match, is ada@example.com. The second match, grace@polyatic.com, yields grace and polyatic.com. Now put $1 [at] $2 in Replace with: because $1 and $2 are back-references to those groups, the output becomes Contact ada [at] example.com or grace [at] polyatic.com for details. — the addresses de-linked while every other character is left untouched. Change \w+ to [\w.]+ and you would also catch dotted local parts like ada.lovelace@…; that is the kind of tweak this live view makes obvious.
Reading the plain-English breakdown
Under the replace preview, the Pattern explained panel walks your regex left to right and names every piece in plain words — updating on each keystroke, exactly like the matcher. A small explicit tokenizer does the work: it does not run your pattern to guess what it means, so the description is honest even when the regex matches nothing. For the loaded /(\w+)@(\w+\.\w+)/g it reads out capturing group 1, the \w word-character class, the + greedy quantifier, the literal @, the escaped literal \., and finally the g flag. It tells greedy from lazy (+ vs +?), distinguishes (?:…), named (?<name>…) and the four lookarounds, spells out character-class ranges and negations like [^a-z], and — crucially — if it hits a part JavaScript's engine rejects, it shows an honest couldn't parse this part marker in red rather than inventing a meaning. Once you know what a pattern does, the sibling Find & Replace Text tool applies it across a whole document with a live preview and whole-word or regex modes.
The six flags, and what each changes
Flags sit after the closing slash and modify how the whole pattern behaves. This tool exposes all six that JavaScript supports:
| Flag | Effect |
|---|---|
g | Global — find every match, not just the first |
i | Ignore case — A matches a |
m | Multiline — ^ and $ hit every line |
s | dotAll — . also matches newlines |
u | Unicode — code-point mode, enables \p{…} |
y | Sticky — match only at lastIndex |
A token cheat-sheet
The building blocks you reach for most, all valid in this JavaScript engine:
| Token | Matches |
|---|---|
\d \w \s | A digit, word char, whitespace |
. | Any char except newline (unless s) |
* + ? | 0+, 1+, 0-or-1 of the previous |
{2,5} | Between 2 and 5 repeats |
+? | Lazy — as few as possible |
^ $ | Start / end (of line with m) |
\b | Word boundary |
(?<n>…) | Named capture group n |
(?:…) | Group without capturing |
(?=…) | Lookahead (assert, don't consume) |
New to the syntax, or want the tokens laid out with worked examples? Learn more: Regex quick reference — character classes and their negations, anchors, greedy vs lazy quantifiers shown side by side, groups, alternation and backreferences, all four lookarounds worked through, and a table of real patterns (email-ish, ISO date, hex colour, US phone) each with an honest note on what it does not catch.
Reading the capture groups
Group 0 is always the whole match. Each pair of parentheses adds a numbered group; (?<user>\w+) creates a named group you read as $<user>. Use (?:…) when you want grouping for a quantifier but do not want a capture — it keeps your group numbers stable. A group that didn't take part in a given match (say one inside an unused alternative) shows as a dash rather than an empty string, a distinction that matters when you branch on it in code.
Common mistakes
Forgetting the g flag then wondering why only the first match highlights, or why .replace() changed just one occurrence. Assuming case-insensitivity — matching is case-sensitive unless you add i. Greedy quantifiers eating too much: <.+> against <a><b> matches the whole string in one go; make it lazy with <.+?> or use <[^>]+>. Unescaped metacharacters: to match a literal dot write \., otherwise . matches any character — 3.14 as a pattern also matches 3x14. Expecting PCRE features: atomic groups, possessive quantifiers and recursion don't exist in JavaScript.
Honest limits and catastrophic backtracking
This is the JavaScript flavour, which differs from PCRE, Python's re and .NET — lookbehind, named groups and \p{…} use JS syntax and there is no recursion. The real danger with any backtracking engine is catastrophic backtracking: a pattern with nested quantifiers over overlapping alternatives, such as (a+)+$ tried against "aaaaaaaaaaaaaaaaaaaa!", forces the engine to try exponentially many ways to split the a's before it gives up, which can freeze a tab for seconds. To blunt that, the test text is capped at 50,000 characters and the global scan stops after 20,000 matches, but because everything runs on the main thread a truly pathological pattern can still pause before the cap bites. If the page feels stuck, simplify the pattern (prefer [^x] classes over .*) or shorten the input.
Why it runs in your browser
Regexes are often written against log lines, config, tokens or scraped data you would rather not hand to a website. Here you don't have to: the page loads no third-party scripts, makes no network calls, and does all of its work — compiling, matching, capturing and replacing — on your own device. Close the tab and everything you typed is gone.