About this regex tester
This regex tester runs your pattern with the browser's own JavaScript RegExp engine, so results match what you get in browser code or Node.js. It builds the expression with new RegExp(pattern, flags), adds the g flag if you left it out, and walks every match with String.prototype.matchAll(). Each match is highlighted and counted, and your text is inserted as plain text, so HTML in it is shown, never run. Nothing is uploaded.
How to use it
- Enter a pattern without the surrounding slashes:
\d+, not/\d+/. - Set flags such as
i,mors.gis always applied. - Paste sample text. Matches highlight as you type, and the count shows above the result.
Worked example
The sample uses the pattern \bcolou?r\b with flags gi on three lines of text. The count is 3: Color, colour and COLOR. The ? makes the u optional, i ignores case, and the two \b word boundaries reject colors and colorful, where a letter follows the r. Delete the final \b and the count rises to 5.
JavaScript regex cheat sheet
Checked against the MDN regular expression cheat sheet and tested in this page's engine.
| Syntax | Meaning |
|---|---|
. | Any character except a line break (with s, line breaks too) |
\d \w \s | Digit 0–9; word character [A-Za-z0-9_]; whitespace, including Unicode spaces |
\D \W \S | The opposite of each |
[abc] [^abc] [a-z] | One character from the set; not in the set; in the range |
\t \n \r | Tab, line feed, carriage return |
\u{1F600} \p{L} | Code point escape and Unicode property; need u or v |
^ $ | Start and end of input (of each line with m) |
\b \B | Word boundary; not a word boundary |
* + ? | 0 or more; 1 or more; 0 or 1 |
{3} {3,} {3,5} | Exactly 3; 3 or more; 3 to 5 |
*? +? ?? | Lazy versions: as few as possible |
(x) \1 | Capturing group; backreference to group 1 |
(?:x) | Group without capturing |
(?<year>\d{4}) \k<year> | Named group, read as match.groups.year; named backreference |
a|b | a or b |
x(?=y) x(?!y) | x only if followed (not followed) by y |
(?<=y)x (?<!y)x | x only if preceded (not preceded) by y |
All eight JavaScript regex flags
| Flag | Name | What it does |
|---|---|---|
| d | hasIndices | Records the start and end positions of each capture group |
| g | global | Finds all matches instead of stopping at the first |
| i | ignoreCase | Ignores the difference between upper and lowercase |
| m | multiline | Makes ^ and $ match at the start and end of each line |
| s | dotAll | Lets . match line breaks |
| u | unicode | Treats the pattern as Unicode code points, enabling \u{…} and \p{…} |
| v | unicodeSets | An upgrade to u with more Unicode features; can't be combined with u |
| y | sticky | Matches only at the current position, not anywhere later |
An unknown letter, or the same flag twice, makes the pattern invalid, and the tester shows the browser's error message. One trap: without u or v, \p{L} is not an error. It quietly matches the literal text p{L}.
Regex examples, with honest caveats
| Use | Pattern | Caveat |
|---|---|---|
| Whole number | ^-?\d+$ | Rejects +1 and 1,000 |
| US ZIP code | ^\d{5}(-\d{4})?$ | Checks the format, not that the ZIP exists |
| US phone | ^\(?\d{3}\)?[-. ]?\d{3}[-. ]?\d{4}$ | Also accepts an unbalanced (555-123-4567 |
| Date YYYY-MM-DD | ^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$ | Accepts 2026-02-31; check real dates in code |
| Email (rough) | ^[^\s@]+@[^\s@]+\.[^\s@]+$ | Accepts a@b..c, rejects ana@localhost; only sending mail proves an address |
| Hex color | ^#([0-9a-fA-F]{3}){1,2}$ | Ignores 4- and 8-digit forms with alpha |
| IPv4 address | ^((25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(25[0-5]|2[0-4]\d|1?\d?\d)$ | Allows leading zeros such as 01 |
| Repeated word | \b(\w+)\s+\1\b with i | Finds is is and the THE |
With m off, ^ and $ anchor to the whole text, so validation patterns like these match only when the box holds a single value. Turn on m to test one value per line.
Catastrophic backtracking
A backtracking engine like JavaScript's tries alternatives one by one. Nested quantifiers over the same characters make that explode. Test ^(a+)+$ against 25 letters a followed by b: the match must fail, but first the engine tries every way to share the a's between the inner and outer +, and 25 a's can be split 224 = 16,777,216 ways. Each extra a doubles the work. In our test in Node.js 22, which uses the same V8 engine as Chrome, 26 a's took about 0.4 seconds; a few more freeze the tab. This page matches as you type, so try such patterns on short text. The fix is to remove the ambiguity: ^a+$ answers the same question instantly. JavaScript has no atomic groups or possessive quantifiers; a++ is a syntax error, so rewriting is the only option.
How JavaScript regex differs from PCRE and Python
- Named groups. JavaScript writes
(?<name>…)and\k<name>. Python'sreuses(?P<name>…)and(?P=name). PCRE2 accepts(?<name>…),(?'name'…)and(?P<name>…). - Possessive quantifiers and atomic groups (
a++,(?>…)) exist in PCRE2 and in Python since 3.11, but not in JavaScript. - Lookbehind length. JavaScript allows any pattern inside a lookbehind. Python requires a fixed width, and PCRE2 requires each branch to have a maximum length.
$before a final newline. Python and PCRE2 (by default) letfoo$match"foo\n". JavaScript doesn't unlessmis on.\dand Unicode. JavaScript's\dis always 0–9, even withu, and so is PCRE2's by default. Python's\dalso matches other scripts' digits, such as Arabic-Indic٣. Python'srehas no\p{…}.
Characters that need a backslash
To match these literally, escape them with \: . * + ? ^ $ { } ( ) | [ ] \, and - inside a character class. The classic bug is example.com, whose dot also matches examplexcom; write example\.com. In a JavaScript string for new RegExp(), double every backslash: "\\d+".
Zero-length matches and a surprising count
A pattern that can match nothing, such as \d*, matches an empty string wherever the real match fails. Against ab12 the count is 4, not 1: empty matches before a and b, the real 12, and one at the end. Use + instead of * to require a character.
Once a pattern works, run it on real text with Find & Replace, which supports regex and capture groups, or tidy the text first with the Text Cleaner so stray spaces and line breaks don't hide matches.
Frequently asked questions
This tool uses JavaScript's native RegExp engine (ECMAScript regex), so patterns behave exactly as they do in a browser console or Node.js. Most syntax is shared with PCRE and Python, but named group syntax, lookbehind rules, possessive quantifiers and what $ and \d match differ, so test in your target language too.
g finds all matches instead of stopping at the first one, i makes matching case-insensitive, m makes ^ and $ match the start/end of each line instead of the whole string, and s lets . match newline characters too.
This tester always searches for every match (it adds the g flag automatically if you leave it out), so the most common causes are an unescaped special character like a literal period or parenthesis, case sensitivity when the i flag isn't set, or ^ and $ matching only the start and end of the whole text when the m flag isn't set.
Only roughly. A simple pattern such as ^[^\s@]+@[^\s@]+\.[^\s@]+$ catches obvious typos, but it accepts some invalid addresses and rejects some valid ones, and no pattern can tell whether a mailbox exists. Use a regex for a quick format check, then confirm the address by sending a message to it.
No. Matching runs entirely in your browser using JavaScript's built-in RegExp object — nothing is uploaded or logged.
The sticky flag makes the regex match only at the exact position given by its lastIndex property, rather than searching ahead through the rest of the string. It is mainly used when writing tokenizers or parsers that read input step by step. Combined with g, as here, matches must follow each other with no gaps.
Your pattern can probably match an empty string, for example because it uses * or ? on everything. JavaScript then records an empty match at every position where nothing longer matches, and each one is counted even though there is nothing to highlight. Requiring at least one character, with + instead of *, usually fixes it.
It is probably catastrophic backtracking. Nested quantifiers such as (a+)+ give the engine an exponential number of ways to try before a match can fail, so each extra character can double the time. Rewrite the pattern so each part of the text can be matched only one way, and test it on short text first.