Regex replace tester
Try a pattern and a replacement template on your own text. The page shows the result, checks it against the browser's own replace, and lists for every match which part of the template produced which text.
Runs in your browser with JavaScript's own RegExp and JavaScript replacement rules. Nothing is sent anywhere.
Special in the replacement: $$ $& $` $' $1–$99 $<name>.
Result
How each match was replaced
How to use
- Enter the pattern (no slashes) and choose flags. Without the
gflag only the first match is replaced. - Enter the replacement. Use
$1to$99for numbered groups,$<name>for named groups,$&for the whole match,$`for the text before it,$'for the text after it, and$$for a literal dollar sign. - Paste the text. The result updates as you type, and the line under it says whether the browser's own
replace()agrees. - Open How each match was replaced to see the template cut into parts and what each part inserted, including the cases where a reference stays literal.
Worked examples
Each output below was worked out by hand from the ECMAScript GetSubstitution rules before it was compared with the browser, and the automated tests repeat the comparison.
Swap two words
Pattern /(\w+) (\w+)/, replacement $2 $1, text John Smith.
Result: Smith John. $1 is "John" and $2 is "Smith", so the template $2 $1 produces "Smith John".
Reformat a date with named groups
Pattern /(?<y>[0-9]{4})-(?<m>[0-9]{2})-(?<d>[0-9]{2})/g, replacement $<d>/$<m>/$<y>, text From 2026-10-02 to 2026-10-09..
Result: From 02/10/2026 to 09/10/2026.. Each date is rewritten as day/month/year by naming the groups; the surrounding text is untouched.
Wrap every match with $&
Pattern /[0-9]+/g, replacement [$&], text a1 b22 c333.
Result: a[1] b[22] c[333]. $& inserts the whole match, so "1", "22" and "333" each get square brackets.
Text before and after the match
Pattern /b/, replacement [$`|$'], text abc.
Result: a[a|c]c. The match is "b". $` is the text before it ("a") and $' is the text after it ("c"), so "b" becomes "[a|c]" and the unmatched "a" and "c" stay: "a[a|c]c".
A literal dollar sign and a group that does not exist
Pattern /(a)/g, replacement $$$1$2, text a-a.
Result: $a$2-$a$2. $$ is one literal dollar, $1 is "a", and $2 stays as the text "$2" because the pattern has only one group.
Two digits that are not a group
Pattern /(a)/, replacement $10, text abc.
Result: a0bc. There is no group 10, so JavaScript reads $1 followed by a literal 0: the match "a" becomes "a" + "0".
A group that did not take part
Pattern /(a)|(b)/, replacement [$1|$2], text b.
Result: [|b]. Only the second alternative matched, so $1 is empty and $2 is "b".
$<name> in a pattern with no named groups
Pattern /(a)/, replacement $<x>, text a.
Result: $<x>. The pattern has no named groups, so $<x> is left as plain text.
Empty matches
Pattern /x*/g, replacement -, text abxd.
Result: -a-b--d-. x* matches five times (see the tester): empty at 0 and 1, "x" at 2, empty at 3 and empty at 4. Each is replaced by "-" and the letters between are kept: -a-b--d-.
How the other flavors write the same idea
These are documentation notes only; none of them is executed on this site.
| Flavor | Numbered group | Named group | Whole match | Literal dollar or backslash |
|---|---|---|---|---|
| JavaScript (executed) | $1 | $<name> | $& | $$ |
PCRE2 pcre2_substitute (notes only) | $1 or ${1} | $name, ${name}, and the JavaScript form $<name> | $0 or $& | $$; backslash is literal unless the extended option is set |
Python re.sub (notes only) | \1 or \g<1> | \g<name> | \g<0> | Backslash escapes are processed; unknown escapes of an ASCII letter are errors |
Java appendReplacement (notes only) | $1 | ${name} | $0: the javadoc says group zero denotes the entire pattern | \$ for a dollar; a backslash escapes the next character |
Go Regexp.Expand (executed engine, template not run here) | $1 or ${1} | $name or ${name} | No whole-match shorthand is documented. A numeric name refers to the submatch with that index; the page does not say what index 0 means in a template, so treat $0 as unclear. | $$ |
RE2 Rewrite (notes only) | \1 to \9 | Not documented in the header | \0 | Backslash-escaped |
- PCRE2. The API documentation lists
$$, $n or ${n}, $<name>, $0 or $&, $`, $', $_ (the whole input) and $+, and says that dollar is the only escape character unless PCRE2_SUBSTITUTE_EXTENDED is set, which adds backslash escapes and the Python form \g<n>. By default, inserting an unset group is an error unless an option says to treat it as empty; in JavaScript it is simply empty. - Python. The documentation says unmatched groups are replaced with an empty string (since 3.5) and that
\g<2>0 is how to write group 2 followed by a zero, because \20 would be group 20. It gives sub('x*', '-', 'abxd') as '-a-b--d-'. - Java. The Matcher documentation says that for
$g the first digit is always part of the group reference and later digits are added only if they form a legal group reference, which is similar in spirit to JavaScript's two-digit rule, and that a literal dollar is written \$. - Go. The documentation says that in the
$name form the name is "as long as possible": $1x means ${1x}, not ${1}x. That is the opposite of what many people expect, and a reference to a missing group is replaced with nothing. - RE2. The C++ header describes rewrite strings with backslash-escaped digits
\1 to \9 and \0 for the whole match.
Limits & gotchas
- Only JavaScript replacement is executed. The table for the other flavors comes from their documentation and is not run. In particular this page cannot show you how Python or Java would handle a given template.
- Function replacers are not supported. JavaScript's
replace()also accepts a function; this page covers string templates only. - Group names are read from the pattern. If the pattern has named groups,
$<name>works; if it has none,$<stays literal, exactly as the specification says. - Matches are capped. The page replaces up to 10,000 matches and describes the first 20 in detail.
- A time limit applies. A pattern that backtracks catastrophically is stopped after the chosen limit, and the Worker is restarted. See the backtracking page.
FAQ
What does $& insert, and what is the difference between $& and $1?
$& inserts the whole matched substring. $1 inserts only what the first capturing group matched. With the pattern (\d+)px on "12px", $& is "12px" and $1 is "12".
Why did my $10 turn into the first group followed by a zero?
In JavaScript, $nn is read as a two-digit group number only if the pattern has at least that many groups. Otherwise the replacement uses $n followed by the second digit as ordinary text. To be unambiguous with many groups, use named groups and $<name>.
Is the replacement run through the browser or re-implemented?
Both. The page runs your pattern with the browser's RegExp in a Web Worker, applies the replacement template with its own implementation of the ECMAScript GetSubstitution algorithm so it can explain each piece, and then compares the result with the browser's own String.prototype.replace. If the two ever differ, the page says so.
Can I test Python, Java, Go or PCRE2 replacement syntax here?
No. Only the JavaScript replacement is executed. The notes below the tool summarise how those languages write backreferences in a replacement, from their documentation, and are labelled "notes only, not executed".
Why does replacing x* give an extra dash?
Because x* can match the empty string. In "abxd" the matches are empty at 0 and 1, "x" at 2 to 3, empty at 3 and empty at 4, so replacing each with a dash gives -a-b--d-. Python 3.7 and later documents the same result; Go gives -a-b-d- because it skips an empty match that touches the previous match.
Sources
- ECMA-262: GetSubstitution (22.1.3.19.1) Used for: The exact algorithm for $$, $`, $&, $', $n, $nn and $<name>, including the two-digit fallback and the no-named-groups rule.
- MDN: String.prototype.replace() Used for: Replacement patterns $$ $& $` $' $n $<Name> and their meaning.
- MDN: Named capturing group: (?<name>...) Used for: Names must be unique within a pattern, except in different alternatives; groups object; unmatched named group is undefined.
- MDN: Capturing group: (...) Used for: Numbering by opening parenthesis, undefined for unmatched groups, last-iteration capture rule.
- PCRE2: pcre2api Used for: Match limit (PCRE2_ERROR_MATCHLIMIT), default newline, DOLLAR_ENDONLY, pcre2_substitute replacement syntax ($1, ${1}, $<name>, $0 or $&).
- Python docs: re: Regular expression operations (3.13) Used for: Syntax, (?P<name>), atomic groups and possessive quantifiers (3.11+), fixed-length lookbehind, Unicode \d \s \w, $ before trailing newline, \A \Z, re.sub replacement syntax, inline flags at start only (3.11+).
- Oracle (Java SE 21): java.util.regex.Matcher: appendReplacement Used for: Replacement syntax $g, ${name}, backslash escapes.
- Go: regexp package Used for: Linear-time guarantee, leftmost-first semantics, Expand template syntax ($1, ${name}, $name longest-name rule).
- Google RE2: re2.h (rewrite syntax) Used for: Rewrite strings use backslash-escaped digits \1 to \9 and \0.
- MDN: Worker: terminate() Used for: terminate() stops a Worker immediately without letting it finish.
Every document above was opened and read on 2026-10-02. Documentation changes; if a page here disagrees with the current docs, trust the docs and tell us.