Regex Tester
Test JavaScript regular expressions live. See matches, capture groups, and apply replacements as you type.
Enter input above to see the result.
Match, capture, replace
Regular expressions are dense and unforgiving. The way to write one that actually works is iteratively — pattern, sample text, see what matches, adjust. This tool gives you that loop in your browser using the JavaScript engine's native RegExp, plus capture-group inspection and a replacement preview. Patterns and inputs never leave the page.
Typical starting points
- Validating user input (email-shaped, phone-shaped, postcode-shaped) and seeing exactly which inputs pass and fail.
- Parsing log lines, extracting fields, building log filters.
- Designing find-and-replace patterns before running them across a real codebase.
- Debugging a regex you copied from Stack Overflow that doesn't work — paste it here, see what it actually matches.
Patterns worth memorising
\b\w+@\w+\.\w+\b— email-ish^\s*$— empty/whitespace-only line (withmflag)(?<year>\d{4})-(?<month>\d{2})— named capture groups(?:.*)— non-capturing group(?=foo)/(?!foo)— lookahead / negative lookahead
Flags, greediness, and the JS engine
- JavaScript ≠ PCRE. No
\K, no recursive patterns, lookbehind only since ES2018. Patterns from Perl, PHP, or Python often need adjustment. - Without
gflag you get the first match only. Addgfor "find all"; combine withmif anchors should match per-line. - Greedy vs lazy.
.*grabs as much as possible;.*?grabs as little. The difference between matching<b>hi</b> and <i>there</i>as one block vs two. - Anchors at line vs string boundaries.
^and$match string ends by default; withmflag they match each line. - Replacement specials.
$&is the whole match;$1,$2, … are capture groups;$$is a literal$. Forgetting that is a common source of "why is my regex eating my dollars". - Don't parse HTML with regex for anything serious. The classic warning is true: nested tags, comments, and CDATA need a real parser. Regex is fine for one-off log scraping or controlled inputs.
Catastrophic backtracking and Unicode traps
- Catastrophic backtracking is the silent regex killer. Patterns like
(a+)+bcan take exponential time on inputs that don't match — the engine tries every combination of how the innera+could subdivide the input. On modern engines (V8 since 2020) most cases short-circuit, but older engines and certain pathological patterns still hang the page. If a regex test takes more than a fraction of a second on short input, you have a problem. - Unicode awareness is opt-in. By default,
\win JavaScript regex matches only ASCII[A-Za-z0-9_]— not "é", not "中", not "العربية". To get Unicode-aware matching, add theuflag, and for full Unicode property classes (matching every letter regardless of script), use\p{L}with theuflag. Email validators and "word" matchers written without these silently fail on non-ASCII text. - Greedy vs lazy is about backtracking direction.
.*greedy consumes everything then backs off;.*?lazy consumes nothing then expands. Same final match on simple inputs; very different performance on complex ones. Default to lazy when you have an explicit terminator (.*?</div>is almost always what you want, not.*</div>). - For production validators, write tests, not regex. Common regex mistakes — over-permissive email validators that accept
foo@bar, IP-address patterns that match999.999.999.999, URL patterns that miss IDN domains — are best caught by a unit-test suite with real-world positive and negative examples. The regex itself is the implementation; the tests are the spec.
Reformatting dates with capture groups
Enter the pattern (\d{4})-(\d{2})-(\d{2}) with the g flag against 2026-08-21 and 2025-12-01. Both dates highlight, and the groups panel reads Match 1 at index 0 — full: 2026-08-21, $1: 2026, $2: 08, $3: 21, then Match 2 for the second date. Type $3/$2/$1 into the replacement box and the preview becomes 21/08/2026 and 01/12/2025. Delete the g flag and only the first date matches — a non-global regex stops after one hit.
Single matches, literal dollars, lookbehind errors, and \w scope
Why does my pattern only match once? No g flag. Without it, RegExp.exec returns the first match only. Add g for find-all; add m as well if you want ^ and $ to anchor to each line rather than the whole string.
How do I put a literal $ in the replacement? Write $$. In the replacement field $1/$2 are capture groups and $& is the whole match, so a bare $ has to be escaped as $$.
My lookbehind / atomic group throws an error. This runs the browser's native JavaScript engine, not PCRE. Lookbehind (?<=…) only works in modern engines, and there's no \K, no recursion, and no atomic groups. Patterns lifted from PHP or Python often need adjusting.
Does \w match accented or non-Latin letters? Not by default — \w is ASCII [A-Za-z0-9_] only, so "café" or "中文" won't fully match. Add the u flag and use \p{L} for Unicode-aware letter matching.
Backtracking: why regex is powerful and occasionally explosive
A regex engine walks your pattern against the text one position at a time, and the crucial behaviour is backtracking: quantifiers like * and + are greedy, grabbing as much as they can, then giving characters back when the rest of the pattern fails to match. That give-and-take is what makes regex powerful and also what makes it occasionally explode — nested quantifiers on failing input can force exponential backtracking (catastrophic backtracking), hanging on a string only slightly longer than the ones that worked. Anchors (^ $), character classes, and lazy quantifiers (*?) exist largely to constrain that search and keep it linear.
When regex is the wrong tool entirely
Reaching for regex on nested or recursive structures — HTML, JSON, balanced brackets — which are not regular languages and cannot be matched reliably by a regex, only approximated until an edge case breaks it. Use a real parser for those. The everyday slip is forgetting that . doesn't match newlines by default and that * is greedy, so one unanchored pattern quietly swallows far more than intended.
Related
Keep syntax handy with the regex cheatsheet, clean up model output with the regex for LLM output tool, and compare before/after text in the text diff. The high-leverage subset: the 20% of regex worth learning.