Also available in: Español · Português · Français · العربية
Regex Tester
Test JavaScript regular expressions against real text and see matches, capture groups and replacements update as you type — running in a Web Worker, so a runaway pattern cannot freeze the tab.
What is a regex tester?
A regex tester is a page that takes a regular expression and a piece of text and shows you, as you type, exactly what the pattern matches — not what you assume it matches. This one runs entirely in your browser: type a bare pattern such as ^\d+$ or paste a full JavaScript literal like /^\d+$/gi and it reads the flags off the end automatically. Eight flag toggles (g, i, m, s, u, v, y, d) sit next to the pattern field so you can turn behaviour on or off without retyping anything, and a separate test-string box holds whatever text you want to check the pattern against.
The output updates live: a match count and the number of milliseconds the matching took, the test string with every match highlighted in place, and a table listing each match's position, the matched text, its numbered capture groups, and any named capture groups. An optional replacement field shows what the replacement would produce, understanding $1, $<name> and $& the same way JavaScript's own replace does. Because it runs in your actual browser, it also reports which newer regex features that specific browser supports at runtime — lookbehind, named groups, Unicode property escapes, the d flag and the v flag — rather than assuming a spec version it cannot verify.
How to use it
- Enter your pattern. Type a bare pattern like ^\d+$ or paste a full literal like /^\d+$/gi and the flags are read off the end for you. Use the eight flag toggles (g, i, m, s, u, v, y, d) to change behaviour without retyping the pattern.
- Paste your test string. Drop your text into the test-string box and watch the match count, the timing in milliseconds, and the highlighted matches update as you edit either field. The match table below shows each match's position, matched text, and its numbered and named capture groups.
- Add a replacement, if you need one. Type a replacement string using $1, $<name> or $& to reference capture groups, and the tool shows the exact result of applying it to the test string. Leave it blank if you only want to inspect matches.
Why a bad pattern can hang a server
A pattern like /^(a+)+$/ has a nested quantifier: one + inside a group that itself repeats with another +. Against a string that ultimately cannot match, such as a run of the letter a followed by an exclamation mark, the engine cannot just fail fast. It has to try every way of splitting that run of a's between the inner group and the outer group before it can conclude there is no match, and the number of ways to split a string grows exponentially with its length. That is catastrophic backtracking, and it is a property of the pattern, not of any particular input.
The growth is measurable and it is steep. On the same JavaScript engine Chrome uses, matching /^(a+)+$/ against 22 a's plus a trailing exclamation mark took 19 milliseconds; 24 a's took 73; 26 took 293; 28 took 1,170. Each extra character roughly doubles the work, and extrapolating that doubling forward, around 38 a's would take on the order of twenty minutes — an extrapolation, not something anyone measured directly. For contrast, /^a+$/, doing the same job without the nested quantifier, matched against 100,000 a's in 0.12 milliseconds. Same task, no exponential blowup: the difference is entirely in the pattern.
This is why matching runs in a Web Worker here. A regular expression that backtracks catastrophically never returns, and there is no timeout or check you can insert to interrupt it, because control never comes back to your code until the engine finishes — and it never finishes. Running the match off the main thread and terminating that thread is the only way to stay responsive. So this tool can show you the hazard safely: type a pattern that hangs, and after 2 seconds it is stopped and reported rather than freezing the tab, which is exactly what a server without that safeguard cannot do for itself.
Some engines sidestep the problem entirely rather than defend against it. Go's regexp package and RE2 do not support backreferences at all, and in exchange they cannot backtrack catastrophically, full stop, because their matching algorithm never backtracks. That trade — giving up a feature to remove a whole class of denial-of-service bug — is exactly why some systems refuse to support it.
Honest limitations
This tester matches JavaScript regular expressions only, because it runs in your browser using the browser's own engine: results are authoritative for JavaScript and only indicative for anything else. JavaScript's flavour is missing features other flavours have, including atomic groups, possessive quantifiers, recursion, \A or \z anchors, and conditionals. A pattern copied from a PCRE, Python or Perl answer may simply fail to compile here — not because it was wrong, but because the flavour differs in kind, not just in syntax.
The u flag changes what counts as one character, but not all the way to what a reader means by the word. Without u, the dot matches UTF-16 code units, so the thumbs-up emoji counts as 2 matches; with u it counts as 1 code point. But the family emoji — man, woman, girl, boy joined together — is 7 code points and still just 1 visual character, so even with u set, matching what people see as a single character needs more than a flag can give you. The \d shorthand has a similar gap: in JavaScript it is ASCII-only, so it will not match the Arabic-Indic digits ٣٤, while \p{Nd} with u does.
A regex object created with the g flag keeps a lastIndex property between calls, so calling .test() repeatedly on the same string with the same regex object returns true, then false, then true, then false — a bug people hit constantly in their own code, and not a defect of this tool. A related trap is a pattern that can match the empty string, such as /a*/g: a naive match loop never advances past an empty match and runs for ever, so the position has to be advanced by hand, and by a whole code point when u is set, or it lands between the two halves of a surrogate pair where nothing can ever match. This tool handles that internally, but it is worth knowing if you are writing the equivalent loop yourself.
Two more limits are deliberate rather than accidental. The match table stops filling in past 1000 matches, and any pattern still running after 2 seconds is terminated with a message saying so instead of being left to spin. Both exist for the same reason: a pattern that matches enormously often, or matches catastrophically slowly, would otherwise make this page as unresponsive as the bug it exists to reveal.
Why is it free?
This tool is free because it runs entirely on your own device. There is no account to create, no watermark on anything it produces, and no test string or pattern is ever uploaded anywhere: the matching happens in a Web Worker inside your browser, using your browser's own regex engine, and nothing leaves your machine.
FreeToGenerate.com is a collection of tools built the same way: no sign-up wall, no artificial limits designed to push you toward a paid tier, just a working tool on its own page. That is sustainable precisely because tools like this cost nothing to run at scale — your browser does the computing, not a server we would have to pay for.