Find and replace across a block of text with plain
matching or JavaScript regex, including capture groups such as
$1. Add several rules and they run top to bottom, each
on the output of the one before. The Result panel highlights the
text the rules wrote, so you can check every replacement before you
copy the result.
Rule 1 find: (\d{4})-(\d{2})-(\d{2})
replace: $3/$2/$1
Rule 2 find: acme\.test
replace: example.com Order #1042 shipped on 2026-09-28 to ops@acme.test
Order #1043 shipped on 2026-09-29 to billing@acme.test
Order #1044 pending since 2026-09-30, contact ops@acme.test Order #1042 shipped on 28/09/2026 to ops@example.com
Order #1043 shipped on 29/09/2026 to billing@example.com
Order #1044 pending since 30/09/2026, contact ops@example.com Insert a numbered or named capture group. A group that did not take part in the match inserts nothing, and $& inserts the whole match.
Typed as two characters in the Replace box, they become a real newline or tab. Write \\n for a literal backslash followed by n.
Inserts a literal dollar sign. With Regex off, nothing in the replacement is special, so $1 is inserted as the two characters $ and 1.
In plain mode, a word character is a letter, digit or underscore in any script, so caf does not match inside café. In Regex mode, only ASCII letters, digits and underscore count, as with \b.
Each rule runs on the output of the rule above it. Replace foo with bar and then bar with baz, and every foo ends up as baz. That is what you want for a cleanup chain, such as normalizing whitespace, then fixing punctuation, then renaming. However, it breaks a swap of two words. For a swap, go through a placeholder: a to TMP, b to a, TMP to b.
The match count next to each rule is how many times that rule matched the text it received. The highlight in the Result panel marks text written by any rule. A replacement with an empty string removes text and leaves nothing to highlight, so review deletions in the diff checker. Patterns are JavaScript regular expressions: lookbehind and named groups work, while possessive quantifiers and \A do not. Debug a tricky pattern in the regex tester first, where you can see each match and group.
const text = "Order 2026-09-28 shipped to ops@acme.test";
// Literal, every occurrence. replaceAll with a string never treats it as a pattern.
console.log(text.replaceAll("acme.test", "example.com"));
// Regex with capture groups: $1, $2... or $<name>
console.log(text.replace(/(\d{4})-(\d{2})-(\d{2})/g, "$3/$2/$1"));
// A function replacer when the new text depends on the match
console.log(text.replace(/\b\w+@\S+/g, (m) => m.toUpperCase()));
// User input inside a regex must be escaped first
const escape = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
console.log(text.replace(new RegExp(escape("acme.test"), "gi"), "example.com")); String.prototype.replace() with a string pattern replaces only the first match. Use replaceAll() or a regex with the g flag to replace every match.
<?php
$text = "Order 2026-09-28 shipped to ops@acme.test";
// Several literal pairs. str_replace applies them in order, like the rules here.
echo str_replace(["acme.test", "Order"], ["example.com", "Ticket"], $text), "\n";
// strtr replaces all pairs in one pass, so a swap works
echo strtr("cat chases dog", ["cat" => "dog", "dog" => "cat"]), "\n"; // dog chases cat
// Regex with groups. $1 or ${1} in the replacement.
echo preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '$3/$2/$1', $text), "\n";
// Escape user input before building a pattern
$needle = preg_quote("acme.test", "/");
echo preg_replace("/$needle/i", "example.com", $text), "\n"; import re
text = "Order 2026-09-28 shipped to ops@acme.test"
print(text.replace("acme.test", "example.com"))
# Python uses \1 or \g<1> for groups in the replacement, not $1
print(re.sub(r"(\d{4})-(\d{2})-(\d{2})", r"\3/\2/\1", text))
print(re.sub(r"(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})", r"\g<d>.\g<m>.\g<y>", text))
# re.escape for literal user input, flags for case-insensitive and multiline
print(re.sub(re.escape("ACME.TEST"), "example.com", text, flags=re.IGNORECASE))
print(re.sub(r"^", "> ", "line one\nline two", flags=re.MULTILINE)) In Python, $1 in a replacement is literal text. Use \1 or \g<1>, and a raw string so the backslash survives.
The highlight marks text produced by any rule and follows it through the later rules, so you can see what changed without running a separate diff. A replacement with an empty string removes text and leaves nothing to highlight, so use the diff checker to review deletions.
This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.
Turn on Regex, wrap part of the pattern in parentheses, and refer to it as $1, $2 and so on in the Replace box. Named groups (?<year>...) are inserted with $<year>, $& inserts the whole match and $$ is a literal dollar sign.
Turn on Regex and type \n in the Replace box, or \t for a tab. In plain mode a backslash has no special meaning, so the two characters are inserted as typed.
Yes. Click Add Rule for each extra find and replace pair. Rules run top to bottom, each on the output of the one before, and each shows its own match count.
JavaScript regular expressions, always with the g flag, plus i when Match case is off and m when Multiline is on. Lookbehind and named groups work; possessive quantifiers, atomic groups and \A do not.
The pattern is not a valid regular expression, and the rule shows the browser's own error message. The usual causes are an unescaped ( or [, or a + or ? with nothing before it. The tool skips the broken rule and still runs the others.
Build and debug the pattern in the regex tester, check what a replacement changed with the diff checker, or clean up a list with remove duplicate lines and the case converter.