How to use it
Type a pattern without the slashes, switch flags on with the chips, and put the text to search in Test text. Every match is tinted in place, in alternating colors so neighbors stay apart, and the table below lists each match with its position and its groups, numbered and named. Positions count UTF-16 code units, as match.index does.
- Tick Replace matches to see what
text.replace(regex, replacement)returns.$1and$<name>insert groups,$&the whole match and$$a dollar sign. - What the pattern means breaks the pattern into its pieces, with groups, classes and alternatives nested under the piece that holds them. Point at a line to see its piece marked in the pattern.
- Warnings appear above the matches when the pattern can backtrack catastrophically, or when the text suggests a missing flag.
- Copy as a JS literal copies the pattern with its flags, escaped as JavaScript writes it:
/\d+\/\d+/g.
The pattern runs in your browser’s own RegExp, the engine your JavaScript runs, in a background worker. If a pattern is still running after a second, the page stops it and says so instead of freezing the tab.
Examples
Dates rewritten from ISO order, with named groups and the g flag:
pattern (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})
replacement $<day>/$<month>/$<year>
text Released 2026-10-14, patched 2026-11-02.
There are two matches, 2026-10-14 at 9–19 and 2026-11-02 at 29–39, and the first one’s groups are year 2026 at 9–13, month 10 at 14–16 and day 14 at 17–19. After replace():
Released 14/10/2026, patched 02/11/2026.
\w is ASCII, even with the u flag. On café naïve, \b\w+\b with g finds three matches, not two:
caf 0–3
na 5–7
ve 8–10
\p{L}+ with gu finds café and naïve, because \p{L} means a letter in any script.
A pattern that nests one repeat in another, ^(\w+\s?)*$, gets this warning on the text an almost matching line!:
"(\w+\s?)*" repeats "\w+", which repeats too. On text that almost matches, the engine tries every way to split the text between the two, and each extra character can double the work (catastrophic backtracking). Rewrite it so each character can be matched only one way.
^\w+(?:\s\w+)*$ matches words separated by single spaces with one way to split them, because each round has to start with a space, which \w can’t take. It gets no warning.
Good to know
- Without
g, JavaScript stops at the first match.\d+on3 apples and 12 pearsfinds only3, andreplace()changes only that one.matchAll()andreplaceAll()with a regex throw aTypeErrorwithoutg. gandymake a regex remember where it stopped.exec()andtest()start atlastIndexand move it on, so reusing one/gregex withtest()alternates:
const re = /a/g;
re.test('a'); // true, and lastIndex is now 1
re.test('a'); // false: the search started at 1, and lastIndex goes back to 0
y(sticky) never searches ahead. A match has to start exactly atlastIndex. Withgy, matches have to follow each other with no gap, which is how tokenizers are written.\b,\wand\dare ASCII-only.\bsees a boundary insidecafé, betweenfandé. For words in any language, use\p{L}withu, and lookarounds such as(?<!\p{L})instead of\b.ucounts code points. Without it,.matches half of an emoji and\p{L}is the textp{L}. With it, the syntax is strict: an escape that means nothing, such as\-outside a class, is an error.visuwith set operations.[\p{L}--[a-z]]is a letter that isn’t a–z,&&intersects,\q{…}matches whole strings, and\p{RGI_Emoji}matches multi-character emoji. Inside a class,vwants(,),[,{,},/,-and|escaped. It needs Chrome 112, Firefox 116, Safari 17 or Node 20.- Lookbehind can be any length.
(?<=\$)\d+works, and so does(?<=\$\s*), which Python’srerejects. Safari added lookbehind only in 16.4, in March 2023. $means the very end. Withoutm, Python and PCRE also accept a position before a final newline; JavaScript doesn’t, so/abc$/fails on"abc\n".- Things PCRE and Python have that JavaScript doesn’t: possessive quantifiers (
a++) and atomic groups ((?>…)) are syntax errors,\Aand\zdon’t exist, and named groups are(?<name>…), where Python writes(?P<name>…). Python’s replacement strings use\1and\g<name>where JavaScript uses$1and$<name>. Inline flag groups such as(?i:…)are new in ES2025 and Node 22 still rejects them. - The list stops at 1,000 matches and says there are more.
replace()still runs over the whole text.
Questions
How do I test a regex in JavaScript?
Paste it here, or call /pattern/flags.test(text) for a yes or no, text.match(regex) for the first match, or [...text.matchAll(regex)] with g for every match and its groups. This page runs the same engine as your code, so what matches here matches there.
Why does my regex only find the first match?
It has no g flag. match(), exec() and replace() stop after one match without it. The tester warns when the text has more matches than a pattern without g reports.
Why does test() return true, then false, on the same string?
The regex has g or y, so test() starts from lastIndex, which the first call moved to the end of the match. Drop the flag for yes-or-no checks, or set re.lastIndex = 0 before each call.
What is catastrophic backtracking?
A pattern such as (a+)+$ can split the same text between its two repeats in exponentially many ways. When the match finally fails, the engine tries them all, and 30 characters can take seconds. JavaScript’s engines have no time limit, so one bad pattern can freeze a page or hold a server. Make each character matchable one way only.
How do I match a letter in any language?
Use \p{L} with the u or v flag: /\p{L}+/u matches café, Ζεύς and 東京 whole. [a-zA-Z] and \w stop at the first accented letter.