Regex Tester & Match Debugger

Type a pattern, paste test text, and watch matches highlight live with capture groups, replace preview, and unit tests. Nothing leaves your browser.

ZERO UPLOAD · ALL LOCAL
  1. Type a regular expression in the pattern field and toggle the g, i, m, s, and u flags you need. Matching runs automatically as you type.
  2. Paste your test text into the editor below. Every match highlights inline, and each capture group gets its own tint.
  3. Step through matches with the arrows above the inspector to see the full match and every capture group with its exact character range.
  4. Switch to Replace to preview substitutions live, using $1 or $<name> references in the replacement field.
  5. Switch to Unit Tests to pin the pattern down: add test strings, mark each as should match or should not match, and watch the pass count update.
  6. Click Share to copy a link that reproduces your pattern, flags, text, and test cases, or open Explain to read the pattern token by token.

Output (Replaced text)

  

Unit tests

How live match highlighting works

Paste a block of log output, type a pattern, and every match lights up before you finish the thought. The tester runs your pattern through the browser's native RegExp engine on a short debounce, so feedback arrives as you type instead of after a button press. Highlights render in an overlay that sits pixel-aligned behind the text you are editing, which means you keep your cursor, your selection, and your scroll position while you experiment.

How capture groups are tinted

Capture groups get their own treatment. Behind the scenes, the tool compiles every pattern with the hasIndices flag, which makes the engine report the exact start and end offsets of each group rather than forcing the tool to guess by re-searching substrings.1 Each group receives one of five rotating tints inside the wider match highlight, and the inspector beside the editor lists the active match with every group's number, name, text, and character range.

A concrete pattern makes the group inspector easier to picture. Typing (\d{3})-(\d{4}) against the test string Call 555-1234 now highlights 555-1234 as the full match, with group 1 capturing 555 and group 2 capturing 1234. The inspector lists both groups with their exact character offsets the moment the pattern compiles, so you can confirm the split is landing where you expect before wiring the pattern into real code.

Both forms of parenthesis group. A plain (...) also captures: it takes a numbered slot in the inspector and a $1 reference in Replace mode, while (?:...) groups without capturing, so alternation or a quantifier can wrap a subexpression without consuming a group slot.2 The difference is visible the moment you edit it: swap a (...) for (?:...) and the group's inspector row disappears, while every later group renumbers, since group numbers follow the order of the opening parentheses. Use the capturing form when the inspector or a $1 reference will actually read the text back; for structure alone, the non-capturing form keeps your numbering exactly as planned.

Matching special characters literally

Every metacharacter in a pattern is doing a job. The dot matches almost any character, the question mark makes an item optional, and brackets open a character class, so a literal one needs the backslash: \. matches a period, \? a question mark, and \[ an opening bracket.3 In a string literal, the pattern needs one more step, because the backslash is also an escape in JavaScript strings and has to be doubled inside the string.4 The Explain panel turns that into a fast check, since it names every escaped literal one by one as it walks your pattern, and a paste that lost its backslashes shows up there before it costs you an hour of debugging.

What each flag does

The five toggles beside the pattern field each change one engine behavior. With g on, matching finds every occurrence instead of stopping at the first, and g is also what makes Replace rewrite every occurrence rather than just the leading one.3 The i toggle ignores letter case, so ERROR and error become interchangeable. Under m, the ^ and $ anchors move from the boundaries of the whole input to the start and end of each line, the shape you want when a pattern targets individual log lines.5 The s toggle changes something else entirely: it lets the dot match line breaks. The two are the classic mix-up. Multiline text often needs both, because each flag changes a different thing.

The u toggle is the deepest of the five. It switches matching into Unicode mode, and its biggest payoff is unlocking \p{...} property escapes, so a class like \p{L} can match a letter in any script instead of one alphabet at a time.5 Most everyday patterns run the same with it off, and the toggle ships that way by default. The closing point is practical: flipping any toggle re-evaluates the pattern on the spot, so you can paste a multiline block with m off, switch it on, and watch the highlight show exactly which anchors moved.

Why some patterns freeze other testers

Some patterns can freeze a browser tab solid. A regular expression like (a+)+$ tested against a long run of the letter a forces the engine to try an exponential number of ways to split the input, a failure mode called catastrophic backtracking; security literature names the attack that exploits it ReDoS, short for regular expression denial of service.6 Most online testers run your pattern on the page's main thread, so one careless quantifier stops the whole tab from responding.

How this tester contains runaway patterns

This tool treats that risk as a design requirement. Every evaluation runs inside a dedicated Web Worker, a separate thread that cannot block the page you are looking at.7 If the worker fails to answer within 500 milliseconds, the tool terminates the entire thread, spins up a fresh one for your next keystroke, and tells you which kind of pattern usually causes the blow-up.8 Your tab keeps scrolling the whole time.

This hard stop is what keeps the interface responsive. Once the worker is terminated it cannot resume, so the tester spins up a fresh worker for your next keystroke and hands the new evaluation to it. The main thread never waits on the doomed computation, which is why you can keep typing and scrolling while a runaway pattern is still being abandoned.

Find and replace with group references

Testing a match is only half the job, because most patterns exist to rewrite text. In Replace mode, the match highlighting stays visible on your test string while a second field accepts a replacement template, and the substituted result updates live underneath. You see what will be replaced and what it becomes at the same moment, which catches off-by-one group references before they reach your codebase.

The template follows the exact semantics of JavaScript's String.replace, so whatever works here works unchanged in your code.9 Write $1 or $2 to insert numbered capture groups, $<name> to insert a named group, $& for the whole match, and $$ for a literal dollar sign. When the g flag is on, the engine rewrites every occurrence; without it, only the first. Because replacement runs through the same worker and timeout guard as matching, a pathological pattern cannot freeze the preview either.

By default, quantifiers are hungry. A .* or a .+ takes the longest run it can, which is why a replacement built on .* so often swallows more of the line than you intended; appending ? turns the quantifier lazy, so it stops at the shortest match that still satisfies the pattern.10 Because the live highlight draws the consumed span the moment the character lands, you see both behaviors side by side as you edit, and the Explain panel names the lazy variant whenever one is present. If a find-and-replace eats a whole line instead of the fragment you wanted, the fix is usually one character: that trailing ?.

Treat your pattern like code

A regex that works on one happy-path string is not finished. Unit Tests mode lets you pin the behavior down the way you would pin down a function: add a list of short test strings, mark each one as should match or should not match, and watch a live pass count while you refine the pattern. Negative cases matter as much as positive ones, since the most common regex bug is matching more than you intended.

Work through positive and negative cases

For an email pattern, for example, you might assert that [email protected] passes, that a bare word fails, and that a string with two @ signs fails. Every edit to the pattern re-runs all rows in a single batch, and each row shows an immediate PASS or FAIL badge next to its expectation. When you share the link, the whole suite travels with it, so a teammate opens not just your pattern but the evidence that it works.

The Snippets menu saves the blank-field moment. It holds eight curated starting points, one click each into the pattern field: an email address, a URL, an IPv4 address, a phone number, a YYYY-MM-DD date, a hex color, a URL slug, and leading or trailing whitespace. Treat them as editable starting points rather than standards, because every one of them makes judgment calls a stricter product decision might reject: the email pattern accepts plus tags, the slug pattern insists on lowercase, and the date pattern does not check the day against the month. The natural next step is the workflow this section already describes: load one, then pin down its edge cases with test rows until the pattern earns its PASS badges.

Share links without giving up privacy

Nothing you type here leaves your machine. Matching, replacement, unit tests, and the explainer all run inside your browser tab against JavaScript's built-in regular expression engine, and you can cut the network connection after the page loads to confirm it for yourself.9 There is no account, no server-side history, and no request that carries your pattern or test data anywhere.

Sharing works without giving that up. When you click Share, the tool serializes your pattern, flags, mode, test string, replacement template, and unit test rows into a compact encoded string, writes it into the page address, and copies the full link to your clipboard. The state lives entirely inside the URL, so it reaches exactly the people you send it to and nobody else. Until you press that button, nothing is encoded anywhere at all.

Pattern-Is-Working Checklist

  • Capture groups match what you expect Check the inspector lists the right text and character range for every numbered or named group, not just the overall match.
  • No "pattern took too long" warning That message means catastrophic backtracking — nested or overlapping quantifiers such as (a+)+ are the usual cause.
  • Flags match your real code A pattern tested with g or i toggled on behaves differently once those flags are missing in your actual code.
  • Negative test cases fail correctly A regex that only matches the happy path is unfinished — add strings that should not match in Unit Tests mode.

Run your own pattern and test text above and check it against this list before shipping it.

Sources
  1. 1.

    MDN Web Docs, "RegExp.prototype.hasIndices," developer.mozilla.org, accessed July 2026. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices

  2. 2.

    Jan Goyvaerts, "Regex Tutorial: Parentheses for Grouping and Capturing," regular-expressions.info, accessed September 2026. https://www.regular-expressions.info/brackets.html

  3. 3.

    "Regular expression," Wikipedia, accessed July 2026. https://en.wikipedia.org/wiki/Regular_expression

  4. 4.

    Ecma International, "ECMAScript® 2025 Language Specification (String Literals)," ECMA-262, ecma-international.org, June 2025. https://262.ecma-international.org/16.0/#sec-string-literals

  5. 5.

    TC39, "s/dotAll flag for regular expressions," tc39.es, January 2018. https://tc39.es/proposal-regexp-dotall-flag/

  6. 6.

    OWASP Foundation, "Regular expression Denial of Service - ReDoS," owasp.org, accessed July 2026. https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS

  7. 7.

    WHATWG, "HTML Standard: Web workers," html.spec.whatwg.org, accessed July 2026. https://html.spec.whatwg.org/multipage/workers.html

  8. 8.

    MDN Web Docs, "Worker: terminate() method," developer.mozilla.org, accessed July 2026. https://developer.mozilla.org/en-US/docs/Web/API/Worker/terminate

  9. 9.

    Ecma International, "ECMAScript® 2026 Language Specification (String.prototype.replace)," ECMA-262, tc39.es, accessed July 2026. https://tc39.es/ecma262/#sec-string.prototype.replace

  10. 10.

    Jan Goyvaerts, "Regular Expressions Quick Reference," regular-expressions.info, accessed September 2026. https://www.regular-expressions.info/refquick.html

FAQ