Find and Replace — Bulk Text Replace with Regex
Search and replace inside any text — plain or regex, case-sensitive or insensitive, whole-word or substring, single rule or a chained pipeline. Live match counts, Unicode-aware boundaries, every keystroke processed locally in your browser.
How it works
The tool wraps a small, predictable set of JavaScript primitives: String.prototype.matchAll for counting, String.prototype.replace for the actual rewrite, and RegExp for compiling the find pattern. Everything is a pure function — no server call, no shared state, no dependency beyond the standard library.
- Compile. Your find pattern is either escaped (plain mode — every regex metacharacter is replaced with its literal backslash form) or passed through verbatim (regex mode). The global and unicode flags are always set; case-insensitive, multiline, and dot-all flags are added when their toggles are on.
- Whole-word wrap. When the W toggle is enabled, the pattern is sandwiched between two Unicode-aware lookarounds:
(?<![\p{L}\p{N}\p{M}_])before, and(?![\p{L}\p{N}\p{M}_])after. That treats every Unicode letter, digit, or combining mark as a word character, which is what makes "cat" inside "scat" not match and what keeps "කවිය" inside "කවියා" from matching either. - Count. The tool runs
text.matchAll(regex)to iterate every non-overlapping match. Zero-width matches (anchors like^,$, lookarounds) are advanced past automatically by the engine's AdvanceStringIndex algorithm, so the loop terminates even on patterns like/^/g. - Replace. A fresh compiled regex is passed to
text.replace. In regex mode the replacement is passed as a string so$1,$&,$`and friends work per ECMA-262. In plain mode the replacement is passed as a function returning the literal string, which disables the dollar-sign expansion — so a replacement like$10stays as the two characters "$" and "10". - Cross-check. A second counter is run via
replacewith a counting callback. The verified badge stays green only when both counters agree on the number of matches — the invariantcountByMatchAll(t, p) === countByReplace(t, p)holds for every well-formed input.
Multi-rule mode is a thin loop on top of the single-rule path. Rules are applied left-to-right; each rule's output becomes the next rule's input; per-rule counts and any compile errors are surfaced separately so a typo in rule 3 does not silently mask a working rule 4. The pipeline stops at 50 rules, which is well above any realistic codemod or glossary table.
Escape interpretation in the replacement is opt-in. When enabled, a small switch turns \n into a real newline, \t into a tab, \r into a carriage return, and \\ into a single backslash. Unknown escapes (e.g. \q) are left exactly as the user typed them, so a stray backslash is never silently dropped.
Worked examples
Frequently asked questions
Sources & references
- ECMA-262 — String.prototype.replace (replacement-string token rules)
- ECMA-262 — String.prototype.matchAll (iterator semantics)
- ECMA-262 — RegExp objects, flags, and AdvanceStringIndex
- Unicode Technical Report #18 — Unicode Regular Expressions
- MDN — String.prototype.replace (replacement patterns)
- MDN — RegExp reference (flags, Unicode property escapes)
The replacement semantics and Unicode word-boundary handling on this page were last cross-checked on 2026-05-11. The page is reviewed whenever a relevant TC39 proposal lands (e.g. the v flag set operations) or a Unicode TR update changes the property-escape definitions used for whole-word matching.
Related tools
Comments & feedback
Spotted a bug or want an improvement? Tell us — our team reviews every comment, and good ideas get built. Comments are public and anonymous.
Spotted a regex edge case, an unexpected count, or want a new toggle?
Email me at [email protected] — most fixes ship within 24 hours.