Regex Tester & BuilderBeta
Test and explain regex, or build one from blocks
This tool is a beta version still being stabilized. Please let us know if a result looks off.
Test and explain regex, or build one from blocks
Common patterns
Match details
Pattern explanation
Strings this regex could produce
Random strings that match your current pattern — a quick way to sanity-check that it does what you intended (without anchors, a partial match is possible).
Some combinations didn't match the regex and were dropped.
Replace preview
Build a regex from examples
Put one example per line. We build a draft regex that matches all of them — a starting point, not a finished pattern.
Loading…
Working…
0.0
It hasn't frozen — the result will appear when the calculation finishes.
About Regex Tester & Builder
This tool compiles your pattern with the browser's own new RegExp(pattern, flags), so every result reflects the JavaScript (ECMAScript) regex engine. The same pattern can behave differently in Python, Java, PCRE (PHP) or grep; if you are writing a pattern for another language, read the differences below first.
There are two modes. Test mode shows matches, capture groups and a replacement preview, and breaks the pattern into tokens with a plain-English explanation. Builder mode lets you stack blocks such as 'digits', 'literal text' or 'Korean syllables', or paste sample strings, to get a first draft of a pattern.
Where JavaScript regex differs from other flavors
- Without the g flag you get the first match only. The tool says so when g is off. Turn it on for the equivalent of Python's re.findall.
- Named groups are written (?<name>...); in a replacement you use $<name>, $1 for numbered groups and $& for the whole match. Python's re uses (?P<name>...) and \g<name>.
- Lookbehind, (?<=...) and (?<!...), accepts variable-length patterns. Python's re only allows fixed-width lookbehind. Safari was the last major browser to add lookbehind, in March 2023 (Safari 16.4). On older iPhones a regex literal with lookbehind is a syntax error that stops the whole script from loading, not just the one match.
- JavaScript has no atomic groups (?>...) and no possessive quantifiers like a++, which PCRE and Java offer. That removes one of the standard tools for preventing the backtracking problem described below.
- \d, \w and \b are ASCII-only, even with the u flag. \w means [A-Za-z0-9_], so é, ñ and every non-Latin letter count as non-word characters.
What the u flag changes
Without u, a JavaScript string is treated as UTF-16 code units. The emoji 😀 is two code units, so ^.$ does not match it; with u it matches as one character. Unicode property escapes such as \p{Script=Hangul} or \p{L} only have meaning with u (or v). Without the flag, \p is read as a plain letter p, and \p{L}+ ends up matching strange strings like 'p{L}}}'.
Case-insensitive matching changes too. Without u, the long s (ſ, U+017F) is not treated as a case variant of s; with u, full Unicode case folding applies and it matches. This matters for search features on user-generated text, where 'the same word' may be typed with look-alike characters.
Catastrophic backtracking, measured
JavaScript's engine is a backtracking engine: when a match fails, it goes back and revises earlier choices. Give ^(a+)+$ a string of a's followed by !, and the engine tries every way of splitting the a's between the inner and outer repetition before giving up. The number of splits roughly doubles with each extra a.
Running this tool's matching code in Node.js (V8) produced these timings: 24 a's plus ! took about 66 ms, 26 took about 254 ms, 28 about 958 ms, and 30 about 3.9 seconds. The linear pattern ^a+$ on 10,000 a's finished in under 0.1 ms. Absolute numbers depend on the machine, but the shape, four times slower for every two characters, does not.
The tool runs matching in a Web Worker and kills it if it has not finished within 250 ms, then shows a 'took too long' notice, so the page never freezes. Server code usually has no such guard, and a single crafted request can pin a CPU core; that is ReDoS. The fix is to remove the ambiguity: rewrite nested quantifiers so a string can be split only one way. (a+)+ becomes a+, and (\w+\s?)+ becomes \w+(?:\s\w+)*.
Drafting a pattern in builder mode
The builder allows groups nested one level deep, which covers most real-world patterns such as phone numbers, dates and product codes, without a recursive editor. Paste several sample lines and it looks for a shared structure: 010-1234-5678 and 010-9876-5432 produce ^\d{3}-\d{4}-\d{4}$. A draft fitted to samples can be too narrow or too broad, so switch to test mode and try strings that should not match as well as ones that should.
Worked examples
Pulling amounts out with lookbehind
- Input
Pattern (?<=\$)\d+(?:\.\d{2})? flags g Text Total $19.99, tax $1.60, 30 items- Output
19.99, 1.60 (2 matches)
Only numbers preceded by $ match, and the $ itself is not part of the match. 30 has no $ in front of it.
When \b doesn't know é
- Input
Pattern \bcafé\b flags g Text café cafés- Output
1 match: the café inside cafés
Because é is not a word character, there is no boundary between é and the space in 'café ', but there is one between é and s in 'cafés'. The result is the exact opposite of what most people expect.
Reordering a date with named groups
- Input
Pattern (?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2}) replace $<d>.$<m>.$<y> Text 2026-09-22- Output
22.09.2026 (1 replacement)
With names instead of numbers, adding another group later does not break the replacement string.
How to use it
- Type a pattern and flags, or pick one from the common patterns list.
- Paste test text and check the matches and capture groups.
- Optionally enter a replacement to preview the result.
- If you don't know the syntax, draft the pattern in builder mode from blocks or examples.
Frequently asked questions
It works here but fails in Python.
Change (?<name>) to (?P<name>), make lookbehinds fixed-width, and use \1 instead of $1 in replacements.
I get a 'took too long' message.
That is catastrophic backtracking. Look for nested quantifiers that can split the same text in several ways, such as (x+)+ or (x|x)*, and collapse them.
Why doesn't \w match accented letters?
In JavaScript \w is ASCII letters, digits and underscore only. Use the u flag with \p{L} for letters in any script.
One emoji counts as two characters.
Turn on the u flag. Without it the engine counts UTF-16 code units and splits surrogate pairs.
Is my test text sent anywhere?
No. Matching runs in a worker inside your browser tab.
Sources
- MDN: Regular expressions (JavaScript)
- MDN: Lookbehind assertion
- MDN: Unicode character class escape
- OWASP: Regular expression Denial of Service (ReDoS)
- Python docs: re module
Last reviewed: