Test regular expressions without risking the tab
Type a pattern above, paste your test text, and see every match highlighted right away: numbered and named groups per match, a replacement preview for $1 and $<name>, and an explanation of each building block. Everything runs in your browser, on a separate thread with a hard time limit. No upload, no sign-up.
Why would a regex tester freeze at all?
Because a running regular expression cannot be cancelled from the inside in JavaScript. The pattern (a+)+b looks harmless, yet on 30 characters it forces the engine through billions of backtracking steps, because it tries every possible split of the a characters before giving up. While it computes, the whole thread is stuck: no clicks, no scrolling, no error message.
The name for this is ReDoS (Regular Expression Denial of Service), and it is not a laboratory curiosity. On 2 July 2019 a single regular expression with catastrophic backtracking, shipped inside a new firewall rule, brought Cloudflare's global network down for 27 minutes; the company documented the incident in detail itself. If such a pattern can take out a data centre, it will certainly take out a browser tab.
That is why this tool is built the way it is: your pattern runs in a Web Worker, a thread of its own, while the main thread sets an alarm. If the worker does not answer in time it is terminated from the outside and a fresh one is started for the next request. Doing that from the inside is impossible, and that is precisely the difference from a tester that runs foreign patterns on the main thread.
How do you read capture groups correctly?
Every round bracket in the pattern remembers what it matched. (\d{4}) is group 1, the next bracket group 2, and so on. Named groups are clearer: (?<year>\d{4}) carries its purpose in the name and survives any later reshuffling of the pattern. When a bracket only needs to group but not to remember, write (?:…); that saves work and keeps the numbering clean.
The match list shows both side by side. The important distinction is between did not participate and empty: in (a)|(b), a match on b leaves the first group unused, so it has no value at all. A group like (x*) can very well participate and still hold empty text. Confusing the two is how replacements quietly produce wrong output.
What do $1 and $<name> do when replacing?
The replacement field follows the same rules as String.prototype.replace:
$1through$99insert the content of a numbered group$<name>inserts the content of a named group$&inserts the whole match,$`the text before it,$'the text after it$$inserts a single dollar sign
So 24.12.2026 with the template $<year>-$<month>-$<day> becomes 2026-12-24. The preview works on the matches that were already found, so the pattern is never executed a second time. That is not a detail: a second run on the main thread would be exactly the place where the page freezes after all.
Why is there no perfect email regex?
RFC 5322 allows quoted parts, bracketed comments and nested constructs. A fully compliant expression therefore runs to thousands of characters, is nearly unreadable, and still says nothing about whether a mailbox exists behind the address. The HTML standard works around this by defining its own, deliberately simpler pattern for input type="email" and openly labelling that simplification a willful violation of RFC 5322.
The pattern in the library follows the same line: it catches typing mistakes, and promises nothing more. If you really need to verify an address, send a confirmation message; everything else is cosmetics. The same holds for IBAN: the length differs per country (ISO 13616 allows 15 to 34 characters, Germany uses 22), and the actual check digits come from a modulo-97 calculation that no regular expression can perform. A pattern checks the shape, never the substance.
Where do patterns differ between browsers?
Named groups and lookbehind (?<=…) entered the language with ES2018, but did not arrive everywhere at once: Safari has supported lookbehind only since version 16.4 (March 2023). A pattern that runs cleanly in Chrome can throw a syntax error on an older iPhone. If your expression will end up in a customer's browser, it is worth checking here before it goes into the code.
Honest limits
Up to 100,000 characters of test text and 1,000 matches are evaluated; the worker gives up after one second of computation, the alarm in the main thread after 2.5 seconds. The match list shows the first 100 entries in full, while highlighting still covers all of them. For whole log files a command line tool such as ripgrep is the better instrument. And for the most common trap there is no limit, only attention: nested repetition such as (a+)+ or (\w+\s?)* is the blueprint for a pattern that may never come back.