Regex Tester & Debugger
Test and debug regular expressions in real-time with match highlighting and flag support.
Regular expressions are a compact language for pattern matching and text transformation. They power everything from form validation and log parsing to search-and-replace inside a text editor. The same compactness that makes them powerful also makes them error-prone: a single missing backslash or greedy quantifier can change the meaning of a pattern entirely. This regex tester runs your pattern against sample text in real time, highlights every match, and surfaces capture groups so you can iterate without deploying code.
How it works
The tester uses the browserβs built-in ECMAScript regex engine β the same implementation JavaScript uses at runtime. That means the behavior you see here matches what String.prototype.match, RegExp.prototype.exec, or replace will do in production Node.js or browser code. If you are working in a language with a different engine (Pythonβs re, Goβs RE2, .NET, PCRE), the core syntax is shared, but some advanced features differ β see the FAQ at the bottom.
How to use this tool
- Type a pattern in the top field (omit the surrounding
/delimiters β they are implicit). - Toggle flags:
gfor global,ifor case-insensitive,mfor multiline,sfor dotall,ufor full Unicode. - Paste or type test text in the main text area. Matches are highlighted as you type.
- Expand a match to see the numbered capture groups.
Understanding the flags
g(global) β return every match instead of stopping at the first. Required if you wantreplaceto replace more than one occurrence.i(case-insensitive) βAmatchesa. Respects Unicode case folding when combined withu.m(multiline) β^and$match the start and end of each line rather than only the whole string.s(dotall) β the.metacharacter also matches newlines. Withouts,.stops at\n.u(Unicode) β enables full Unicode matching, including code-point escapes (\u{1F600}) and property classes (\p{L}). Recommended for any pattern that handles user-entered text.y(sticky) β matches only at the current position in the string. Useful for writing tokenizers.
Starter patterns
Copy-paste these as a starting point; validate against your real data before trusting them.
- Email (loose, ASCII) β
^[\w.+-]+@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+$ - URL β
https?:\/\/[-\w@:%._+~#=]{1,256}\.[A-Za-z0-9()]{1,6}\b[-\w()@:%_+.~#?&/=]* - IPv4 address β
^(?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d)$ - ISO 8601 date β
^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$ - UUID (any version) β
^[0-9a-f]{8}-[0-9a-f]{4}-[1-7][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$ - Whitespace-only line β
^\s*$ - Leading/trailing whitespace β
^\s+|\s+$
Worked example: extracting numbers with capture groups
Say you want to pull the hour and minute from lines like Event at 14:37 UTC. The pattern (\d{2}):(\d{2}) with flag g produces two matches per line, but more importantly each match has two capture groups. In JavaScript:
const text = "Event at 14:37 UTC; next at 09:05 UTC";
const re = /(\d{2}):(\d{2})/g;
for (const m of text.matchAll(re)) {
console.log(`hour=${m[1]} minute=${m[2]}`);
}
// hour=14 minute=37
// hour=09 minute=05
In this tester you will see the two captures highlighted as groups $1 and $2 under each match.
Catastrophic backtracking
The single most common regex failure mode is catastrophic backtracking: a pattern that takes exponential time on certain inputs and effectively hangs the thread. The classic offender is nested or overlapping quantifiers, for example ^(a+)+$ against a long string of as followed by one b. The engine tries every possible way to distribute the as among the groups before concluding there is no match.
Signs you are at risk:
- Nested quantifiers like
(x+)+,(x*)*, or(x|y)+. - Alternations where the branches share a prefix:
(abc|ab)*. - Greedy
.*or.+followed by a specific anchor.
Mitigations:
- Make quantifiers non-overlapping: prefer
a+to(a+)+. - Use atomic groups if your engine supports them (JavaScript does not yet, but Goβs RE2 and Java do).
- Use possessive quantifiers in engines that support them (
a++). - Add explicit anchors to reduce the search space.
- Set a timeout around user-supplied patterns on the server.
If a pattern freezes this tester in the browser, the engine is doing exactly what it would do in production code β which is a strong signal to rewrite the pattern.
Frequently asked questions
Does this tester match what I will see in Node.js or the browser?
Yes. It runs in your browser and uses the same V8/JavaScriptCore/SpiderMonkey regex engine as the runtime you are deploying to. Behavior matches RegExp and String.prototype methods exactly.
Why does my regex work here but fail in Python or Go?
Different engines implement different subsets of regex. PCRE (Perl, PHP) and .NET support lookbehind, recursion, and named groups that may not exist or may be spelled differently in ECMAScript. Goβs RE2 (also Rustβs default) intentionally drops backreferences and lookaround to guarantee linear time. Always run your regex in the engine that will eventually execute it.
What is the difference between .* and .*??
The unmarked form is greedy: it matches as much as possible. Adding ? makes it lazy: it matches as little as possible. For <a>foo</a><b>bar</b>, the pattern <.*> matches the whole string; <.*?> matches just <a>.
How do I match across newlines?
Either enable the s (dotall) flag so . matches newlines, or use a character class like [\s\S] which works in engines without dotall.
Why is my capture group undefined?
If a group is inside an optional branch that did not match, its value is undefined. For example, in (foo)|(bar) applied to bar, group 1 is undefined and group 2 is "bar". Non-capturing groups (?:...) do not create numbered captures at all β useful when you only need grouping for alternation or quantification.
Privacy note
Patterns and test strings are evaluated entirely in your browser. Nothing you type here leaves your device or is stored anywhere.