Online regex tester for JavaScript regular expressions
This regex tester runs your pattern against sample text as you type, using the same RegExp engine that powers your browser and Node.js. Matches are highlighted in place, every capture group is listed with its value, and a replace preview shows exactly what String.prototype.replace would return. You can fix a pattern here before it ever reaches your code.
What the tester shows you
- Pattern field with flag toggles. Type a bare pattern or paste a literal like
/\d+/gi; the flags after the closing slash are picked up automatically. - Live highlighting. Each match is marked in the test text, so greedy quantifiers that swallow too much are obvious at a glance.
- Match list. Every match with its start and end offset, followed by numbered groups and, where you used
(?<name>…), the group name. - Replace preview. The full text after replacement, refreshed as you edit the pattern, the text or the replacement.
- Explanation panel. A token-by-token breakdown of the pattern in plain English.
- Cheat sheet. Click a token such as
\b,(?=…)or{2,5}to insert it into your pattern.
Example: named groups and a replacement
With the pattern (?<user>[\w.+-]+)@(?<domain>[\w-]+(?:\.[\w-]+)+), the flag g and the text ann.lee@example.com, bob@test.co.uk, the match list shows each match with its offsets and its groups by name:
1 ann.lee@example.com 0–19
user ann.lee
domain example.com
2 bob@test.co.uk 21–35
user bob
domain test.co.uk
Replacements use JavaScript syntax. Reformatting ISO dates with (\d{4})-(\d{2})-(\d{2}) and the replacement $2/$3/$1 turns Due 2024-07-15 and 2024-08-01 into Due 07/15/2024 and 08/01/2024. You can also use $& for the whole match, $<name> for a named group and $$ for a literal dollar sign. Typing \n or \t in the replacement inserts a real line break or tab.
Flags explained
| Flag | Name | Effect |
|---|---|---|
g | global | Find every match instead of stopping at the first one. |
i | ignoreCase | Letters match regardless of case. |
m | multiline | ^ and $ also match at the start and end of each line. |
s | dotAll | . also matches line breaks. |
u | unicode | Treats surrogate pairs such as emoji as one character and enables \p{…} property escapes. |
y | sticky | Only matches at the exact position where the previous match ended. |
Common regex errors and how to fix them
- Only one match appears. Without
gthe tester reports the first match only and says so in the status line. Turn ongto see them all. - "Invalid regular expression: Unterminated group". A
(has no closing). The error text comes straight from the JavaScript engine, so it matches what your app would throw. - The match runs too far.
<.*>on<b>hi</b>matches the whole string because*is greedy. Use the lazy.*?or a negated class like[^>]*. ^matches only once. In multi-line text, add themflag so anchors work per line.- A pattern from PHP or Python fails. JavaScript has no possessive quantifiers, no
\Aor\Zand no inline modifiers like(?i). Paste the pattern into the regex explainer to spot PCRE-only tokens. - Special characters in user input. If you build a pattern from literal text such as
$19.99, run it through the regex escape tool first so.and$lose their special meaning.
To check a pattern from the other direction, the random data from regex generator produces sample strings that match it, which is a quick way to find inputs you did not expect to be accepted.
Privacy
Your pattern and test text are evaluated by the JavaScript engine in your own browser. Nothing is uploaded, so you can safely test against log lines, customer records or other data you would not paste into a server-side tool.
Test a regex in Python
In Python, test a pattern with the re module: finditer() yields every match with its span and groups. This page runs the JavaScript engine, and two syntax differences cause most of the confusion when a pattern moves between the two. Python writes named groups as (?P<name>…) and rejects the JavaScript form (?<name>…), and replacements use \1 or \g<name> where JavaScript uses $1 and $<name>. Also remember that re.match() only matches at the start of the string; use search() or finditer() to scan.
import re
pattern = re.compile(r"(?P<user>[\w.+-]+)@(?P<domain>[\w-]+(?:\.[\w-]+)+)")
text = "ann.lee@example.com, bob@test.co.uk"
for match in pattern.finditer(text):
print(match.span(), match.group(0), match.groupdict())
print(pattern.sub(r"\g<user> at \g<domain>", text))
Change (?P< to (?< and the tester above reports the same two matches, at offsets 0–19 and 21–35.