QiLing Tools
Sign in

🔍Regex Tester - Test & Debug Regex Online

Test JavaScript regular expressions live: enter a pattern and some text, and every match is highlighted in place and listed with its position and capture groups. Named groups show their names ($1 <year>), groups that did not participate are shown apart from groups that matched an empty string, and zero-width matches such as \b, ^ or (?=…) are marked with a bar. Paste a /hello/gi literal copied from JS code and it is split into pattern and flags automatically. Matching runs in a background thread, so a pattern like (a+)+ that backtracks out of control is stopped after 1.5 seconds with an explanation instead of freezing the page. Supports the g, i, m, s and u flags, and everything runs locally in your browser.

Loading tool...

How to use Regex Tester

  1. 1Enter a pattern, or paste a whole /…/flags literal from your code and the flags are ticked for you
  2. 2Paste the text to match against
  3. 3Read the highlights and the group list below; without the global g flag only the first match is found
  4. 4If you are told the pattern backtracks too much, remove nested quantifiers or try shorter text

FAQ

Which regex flavor is this? Is it the same as Python, Java or PHP?
It is JavaScript (ECMAScript), identical to browsers and Node.js. The common parts (character classes, quantifiers, groups, assertions, backreferences) work the same as in most languages. Tested in current Chrome, the usual differences are: Python's named group (?P<name>…) is an error, write (?<name>…); a leading (?i) is an error, tick the i flag or use (?i:…) for part of the pattern; possessive quantifiers like a++ and atomic groups (?>…) are not supported; JS does allow variable-length lookbehind such as (?<=a+), which is looser than Python or Java.
Why do \A, \Z and \p{…} not error but never match?
Without the u flag, JS treats an unknown escape as the letter itself: \A is just A, so \Aabc\Z does not match abc but does match AabcZ (tested). \p{Script=Han} is likewise read as the literal text p{Script=Han}. In JS, use ^ and $ for start and end. With u ticked, \p{Script=Han} matches Chinese characters (4 of them in 祈灵tools中文😀), and invalid escapes like \A become errors, which makes mistakes easier to spot.
Why doesn't . match a newline, or \w match Chinese?
By default . does not match line breaks; tick dotAll s to match across lines. ^ and $ only match the start and end of the whole text unless you tick multiline m: ^\w$ finds 0 matches in a-newline-b without m and 2 with it. \w covers only ASCII letters, digits and underscore, not Chinese; use [\u4e00-\u9fa5], or tick u and use \p{Script=Han}. Emoji take two units in JS, so ^.$ does not match a single 😀 unless u is ticked.
What does 'backtracks too much, stopped' mean?
Some patterns try every possible split of the text when a match fails, and the time grows exponentially; this is called catastrophic backtracking. Tested with (a+)+$ against a run of a's followed by b: 20 a's took 16 ms, 22 took 52 ms and 24 took 189 ms, roughly 4 times slower for every two extra letters, so 40 a's would take hours. This tool matches in a background thread and stops after 1.5 s with a warning, so the page keeps working. The usual cause is nested quantifiers such as (a+)+, (\w+\s?)* or (.*)*, and rewriting them without nesting normally fixes it. The same pattern in server code can be exploited by malicious input (ReDoS).
What do named groups and 'did not participate' mean?
Each pair of capturing parentheses is listed as $1, $2 and so on; a named group written (?<year>\d{4}) shows as $1 <year> and can be referenced as $<year> in replacements. 'Did not participate' means the branch containing the group was not taken, for example group 1 when (a)|(b) matches b; its value in code is undefined. 'Empty string' means the group took part but matched zero characters, as with a(b*)c matching ac. Code has to check for these differently, so they are shown separately.
What happens if I paste /abc/gi? How do I match slashes themselves?
When a whole /…/flags literal from JS code is pasted into the pattern box, the part between the slashes becomes the pattern, the trailing letters are ticked as flags, and a note says what was unpacked; unsupported y, d and v flags are reported as ignored. This happens only for a whole paste: a typed /api/ still matches the slashes literally, and finds 1 match in GET /api/users.
Are all matches shown when there are many?
Up to 10,000 matches are listed; beyond that a note says more were not shown (tested with . on 20,000 characters, which lists the first 10,000 and shows the note). To count more, test the text in parts or run the pattern in code.
Are my files or data uploaded?
No. Everything runs locally in your browser with no network upload, and is discarded when you close the page.
Do I need to sign up or pay?
No. The site is completely free, needs no account and has no usage limits.

Features

  • Live highlighting of every match, with zero-width matches marked by a bar
  • Position and capture groups for each match, with names for named groups
  • Distinguishes groups that did not participate from empty-string groups
  • Pasted /…/gi literals are split into pattern and flags
  • Matching runs in a background thread and stops after 1.5 s, so the page never freezes
  • g/i/m/s/u flags, instant syntax errors, local processing with no upload