Regex Tester
Test a regular expression against sample text, with matches and capture groups highlighted live.
What This Tool Does
This tool tests a regular expression against sample text live, showing every match, its position, and any capture groups — a fast way to verify a pattern actually does what you think before dropping it into real code.
How to Use It
Type a pattern (without the surrounding slashes), toggle any flags you need, and paste your test text. Matches update automatically a moment after you stop typing — evaluation is deliberately debounced rather than run on every keystroke, so a pattern that's still mid-edit and temporarily expensive to evaluate doesn't bog down the page while you're typing it.
The Formula
This uses JavaScript's native RegExp engine directly — the same one your code will actually run against — with the global flag always applied internally so every match in the text is found, not just the first. A fresh RegExp is constructed for every evaluation rather than reusing one across calls, which avoids a real JavaScript-specific bug described below. Test text over 10,000 characters is rejected with a clear message, and matching stops after 1,000 results, both as safeguards against a pathological pattern or input grinding the page.
A Worked Example
The pattern ^([\w.]+)@([\w.]+)$ against a.b@example.com matches the whole string once, with capture group 1 as a.b and capture group 2 as example.com — a simplified email-shaped pattern useful for demonstrating groups, though not a spec-complete email validator. The same pattern against not-an-email produces zero matches, since there's no @ for the pattern to anchor on.
Common Regex Gotchas
Greedy vs. lazy quantifiers produce genuinely different matches. Against the text <a><b>, the greedy pattern <.*> matches the entire string <a><b> — greedy quantifiers grab as much as possible and only give characters back if forced to. The lazy version <.*?> instead matches just <a>, stopping at the first possible close. Reaching for the wrong one is a very common source of a match that "grabs too much."
Special characters need escaping. Characters like . * + ? ( ) [ ] { } | ^ $ \ all have special meaning in a regex — to match a literal period in an IP address or file extension, for example, it needs to be written as \., not a bare . (which matches any character).
A JavaScript-specific gotcha: reusing a global-flag RegExp with .test() gives inconsistent results across calls. When a RegExp has the g flag, it keeps internal lastIndex state between calls to .test() on that same instance — each call resumes searching from where the last one left off. Calling /foo/g.test('foo bar foo') on the exact same regex object four times in a row genuinely returns true, true, false, true — not four trues — because the third call starts searching past both matches, finds nothing, and resets lastIndex back to 0 for the next call. This is a real bug developers hit when a module-level regex constant gets reused across multiple calls; the fix is either dropping the g flag when you only need a yes/no answer, or constructing a fresh RegExp for each check — exactly what this tool does internally to avoid the same trap.
FAQ
- Why does the result take a moment to update after I type?
- Evaluation is debounced by design — this avoids re-running a pattern that might be catastrophically slow mid-edit on every single keystroke, which could otherwise make the page feel unresponsive while you type.
- What's the difference between greedy and lazy quantifiers?
- Greedy quantifiers like .* match as much as possible; lazy quantifiers like .*? match as little as possible. See the Common Regex Gotchas section above for a concrete side-by-side example.
- Why do repeated .test() calls on the same regex give different results?
- A regex with the global (g) flag keeps lastIndex state between .test() calls on the same instance, so results can alternate true/false across calls on identical input. This tool builds a fresh RegExp on every evaluation specifically to avoid that trap.