Skip to content

Regex Tester & Debugger Online Free

Test JavaScript regex patterns with live match highlighting, flag toggles, and capture group inspection.

In your browseryour files never leave your device.

Learn more
⌘Enter re-run · Workers handle expensive runs and time out at 1 s.

About this tool

Regex flavors differ enough that "works on regex101" is not the same as "works in my code." JavaScript regex (ECMAScript) is mostly compatible with Perl-Compatible Regular Expressions but with quiet edge cases — Unicode property escapes need the u flag, lookbehind was a 2018 addition that some target browsers still trip on, and the lack of x (extended) mode means inline comments are not supported the way they are in Python or PCRE. This tester runs your pattern through the native JavaScript RegExp constructor, so if a match works here it works in your fetch handler, your Node CLI, and any modern browser. Toggle flags as pills. Matches highlight in orange directly inside the test string. Capture groups appear in a list below with their index and content. Friendly error messages catch the common syntax slips before you hit "save" on the regex inside your code.

How to regex tester & debugger online free

  1. Type or paste your pattern

    Just the pattern body — no surrounding slashes. e.g. \b[A-Z][a-z]+\b finds capitalized words. The input is a single-line text field so multi-line patterns (with the x flag in other engines) need to be on one line, JavaScript-style.

  2. Toggle the flags you want

    Click the pills for g (find all matches, not just first), i (case insensitive), m (^ and $ match line boundaries), s (. matches newlines), u (full Unicode support). Each flag has a tooltip if you hover. The visible state of the pills tells you at a glance what mode the engine is in.

  3. Paste a test string

    A line, a paragraph, a log fragment, a CSV header — anything. Matches highlight in real time. The test string box is multi-line, so you can drop in a chunk of file content and see how the pattern behaves across lines with and without the m flag.

  4. Inspect captures and counts

    The match list below shows each individual match with its position and any capture groups. Use this to confirm complex patterns are extracting what you think they are. The match count gives you the at-a-glance "did this find 5 things or 50?" sanity check.

Why use this tool

I drop into this tool whenever I am writing form validation. The common pattern — letting an email or a phone number through if it looks "right enough" — is regex, and small mistakes are easy to ship. Testing against ten edge cases (the address with a + alias, the international number with a leading 00, the name with an apostrophe, the email with a subdomain) in 30 seconds catches the over-strict and the over-loose patterns before they break production. The second case is extracting structured data from a log: I paste 20 lines of nginx access log, write a pattern with named capture groups for method, path, and status, and watch the highlight tell me whether the pattern handles the cases I see. The third case is sanity-checking a complex regex from a coworker before deploying — does this pattern really match what the PR description says it does? The fourth is debugging a redirect rule in a CDN config that uses regex matching, where the difference between greedy and lazy quantifiers can cost you a production outage. The fifth is writing find-and-replace patterns for batch editing in VS Code or sed.

Features

Live highlighting in the test string

Every match in the test string is highlighted in orange as you type. No "Run" button. This is the killer feature — you see immediately whether the pattern is too greedy (matches too much), too narrow (misses the cases you want), or matches nothing at all. The highlight color is consistent so multiple matches stand out together; overlapping or adjacent matches stay distinguishable.

Flag pills for g/i/m/s/u

Toggle global, case-insensitive, multiline, dotall, and unicode flags as visual pills. Hover for a tooltip explaining what each does. The match logic is recomputed on toggle so you can A/B test flag combinations instantly — especially useful for figuring out whether m or s is what you want, since they sound similar but do completely different things (m changes how ^ and $ behave; s changes how . behaves around newlines). The u flag enables Unicode property escapes and is required for \p{Letter} and friends.

Named and numbered capture groups

Each match shows its capture groups in a structured list. Named groups (?<year>\d{4}) appear by name; numbered groups by index. If your pattern produces empty captures because of a quantifier you forgot, you see that directly in the breakdown. The match list also shows the position (string index) of each match, which is useful when the same match appears multiple times and you need to know which occurrence is which.

JavaScript engine, not a custom parser

Patterns run through native RegExp via new RegExp(pattern, flags). So behavior — including lookbehind, Unicode property escapes (\p{L}), and the d flag for indices on supported browsers — matches exactly what your runtime will do. Friendly error messages translate the cryptic engine output for the common mistakes (nothing-to-repeat, unterminated group, unmatched bracket) into something readable. Sample patterns load with one click so you can play with capture group syntax without inventing a test case from scratch.

Privacy & security

The tester compiles your pattern with the native JavaScript RegExp constructor and runs it against your test string in the same browser thread. No upload, no server worker, no analytics on the patterns you try. Capture group extraction is the standard match-array indexing you would use in your own code. If your test string contains user data, logs, or anything you would not paste into a chatbot, this is a safer sandbox — the data is in your tab's memory and nowhere else.

Frequently asked questions

Which regex flavor does this support?
JavaScript / ECMAScript regex. That includes lookahead and lookbehind (positive and negative variants), named capture groups via (?<name>...), Unicode property escapes (\p{Script=Greek}, requires the u flag), and the d flag for capture indices on browsers that support it (Chrome 90+, Firefox 88+). PCRE-specific features like atomic groups, possessive quantifiers, and the x flag for verbose patterns with inline comments are not in JavaScript. If you need any of those, write the pattern in Python or PCRE syntax and translate.
How does this differ from regex101 or Debuggex?
Regex101 has a beautifully detailed explanation panel showing what each part of the pattern matches, and supports PCRE, Python, Go, and JavaScript flavors. Debuggex draws a railroad diagram of the pattern. This tool is the fastest path when you specifically want JavaScript behavior and want to test live without leaving a tab. The trade-off is no flavor switcher and no auto-explanation — if you do not know what (?:...) means, regex101 will teach you; this tool just runs it.
My pattern matches in this tool but not in my Python code — why?
Different flavors. Python re uses a slightly different syntax: lookbehind has to be fixed-width in Python (JavaScript has allowed variable-width lookbehind since 2018), \d means [0-9] by default in Python but [0-9] plus other Unicode digits in JavaScript when the u flag is set, and backreferences before the group definition are illegal in Python re but legal in JavaScript. Test in the flavor you will ship with. Regex101 explicitly supports Python mode for exactly this reason.
What is catastrophic backtracking and can I cause it here?
When a pattern with nested quantifiers (like (a+)+) meets a non-matching input, the regex engine can try exponentially many paths before giving up. The tab can freeze for seconds or minutes. JavaScript engines have no built-in timeout for regex execution so this is a real failure mode in production code too — a malicious input can trigger a DOS. If the highlight stops updating, you have probably written something like (a*)*b on a long input. Back the quantifiers off, use specific character classes ([^a]+ instead of .*), or rewrite the pattern to be unambiguous about which alternative wins.
Does lookbehind work?
Yes — modern JavaScript (since 2018) supports both positive (?<=...) and negative (?<!...) lookbehind, with variable-width patterns. All current browsers handle it. If you are targeting old Safari (pre-16.4), check caniuse first; before that version, lookbehind throws a syntax error. For most current targets, lookbehind is a useful pattern that lets you assert context without consuming the matched text.
How do I match across newlines?
Two tools, two purposes. The s flag (dotall) makes . match every character including \n, so a single .* can span multiple lines. The m flag (multiline) leaves . alone but changes ^ and $ to match the start and end of each line rather than the whole string. They are independent — you might want both, or one, depending on the input. Toggle them and watch the highlight to confirm. If you want to match a phrase that may span a line break, dotall is what you want; if you want to anchor patterns at each line's start, multiline.
Named groups versus numbered groups?
Both work in JavaScript. Numbered is shorter — (\d{4})-(\d{2})-(\d{2}) gives you groups 1, 2, 3 for year/month/day. Named is self-documenting — (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}) makes the intent obvious and means downstream code does not break when you reorder groups. I default to named for anything that will live longer than the current session. The .groups property on a match object holds named captures; numbered indexing still works alongside.
Why does the global flag affect the result count?
Without g, exec returns the first match only and the matches list shows just that one. With g, the engine iterates through every non-overlapping match in the string. If you are using match() or replace() in code, the g flag controls the same behavior there. The non-overlapping rule matters: in "aaaa" with pattern aa, you get two matches at positions 0 and 2, not three matches at 0, 1, and 2, because the regex engine consumes the input as it goes.
Can I test pattern replacements here?
Not in this version — the tool focuses on matching and capture extraction. For replacements (where you would want $1, $2, or named backreferences to template the output), use String.prototype.replace in a Node REPL or browser console: "hello world".replace(/(\w+) (\w+)/, "$2 $1") gives "world hello". The pattern testing in this tool tells you whether your match works; replacement is a one-liner once it does.