Match in real time with highlighted results
This tool lets you check a regular expression quickly in your browser. You enter a pattern, some flags and a block of test text, and the page lists every piece of the text that matched, together with the position (index) where each match starts. It uses the browser's built-in JavaScript RegExp engine, so a pattern that works here will work in JavaScript code. It is worth being clear about what it does not do: it does not paint highlights over your text (matches are shown as a list), and it does not do replacements, show capture-group details or generate code. It answers one question only - what does this pattern actually match in this text?
Take the default test text '订单号 A1023,数量 58,价格 199.5' (order number A1023, quantity 58, price 199.5). The pattern \d+ with the g flag returns four matches when run: 1023 (index 5), 58 (index 13), 199 (index 19) and 5 (index 23). The decimal 199.5 has been split in two by the dot. Switch to the 'Integer/decimal' template, -?\d+(\.\d+)?, and you get three matches: 1023 (index 5), 58 (index 13) and 199.5 (index 19). With the email template, [\w.-]+@[\w-]+\.[\w.-]+, run against '联系 zhang.san@example.com 或 li-si@mail.cn', the matches are zhang.san@example.com (index 3) and li-si@mail.cn (index 27). Comparing results like this is a quick way to spot a pattern that is too loose or too strict. All of these results were produced by running the same RegExp logic, not estimated.
There are three usual causes. First, a different regex engine, as noted above. Second, string escaping: in a JavaScript string literal you must double the backslash ("\\d"), whereas in this tool's input box you type a single \d. Do not mix the two when copying. Third, missing flags: if your code does not use g or i, the results will naturally differ.
The message comes straight from the browser's RegExp constructor and normally names the problem. For example, an unclosed parenthesis gives 'Invalid regular expression: /(abc/g: Unterminated group'. Typical causes are unbalanced brackets, a quantifier with nothing to repeat, a character class with a reversed range, or an escape that is not allowed under the current flags. Fix those first and the results will return.
Input is debounced by 300 milliseconds, so matching runs only once you pause. This avoids running a half-typed pattern at every step. It does not remove the risk of catastrophic backtracking: a pattern with nested quantifiers such as (a+)+b on a long run of a characters can still freeze the page. Debouncing only makes that less likely while you are typing. If the page hangs, close the tab and simplify the pattern.
I would not ship them unchanged. The 'Password strength' template uses lookaheads to require a lowercase letter, an uppercase letter, a digit and at least eight characters, but says nothing about other characters. The 'Port number' template spells out ranges up to 65535, yet without ^ and $ anchors it can still match part of a longer number in the middle of text. Treat the templates as a starting point, adapt them to your own rules and test them properly.
The index is the JavaScript string position, counted from 0 in UTF-16 code units. An ordinary Chinese character takes one unit, so in the example '订单号 A' takes five positions (including the space) and the digits 1023 after it begin at index 5. Some emoji and rare characters take two units, which makes later indexes larger than a visual count would suggest.
Matching happens entirely in your browser using the built-in RegExp engine. The code makes no network request with your pattern or test text, and nothing is saved when you close or refresh the page. If you paste sensitive text into the test box, it stays in the memory of that page only, but it is still sensible not to leave the page open on a shared computer.