Skip to content
Find and Replace

Find and replace text — literal, regex, capture groups and a list of rules

Replace text in your browser, with the matches highlighted before you commit and a count of what changed. Literal by default, so a full stop means a full stop; regex when you switch it on, with $1 for capture groups and the i, m, s and u flags spelled out rather than assumed. Or write several find-and-replace pairs and run them in order, which is the thing a code editor makes you do one at a time. Regex patterns run on a separate worker thread with a time limit, so a runaway one cannot take your tab with it. Nothing is uploaded or saved.

  • Nothing is uploaded or saved
  • Works offline
ModeLive as you type — literal text is escaped, so it cannot backtrack
Rule

Every character means itself here — a full stop is a full stop and brackets are brackets. Whole word uses \p{L} and \p{N} rather than \b, because \b in JavaScript is defined over [A-Za-z0-9_] only and gets café wrong.

Your text
Matches highlighted
INV-2026-014  Kedai Kopi Sdn Bhd      RM 1,240.00
INV-2026-015  Kedai Kopi Sdn Bhd      RM   980.50
INV-2026-016  Warung Nasi Sdn Bhd     RM 2,115.75
INV-2026-017  Restoran Melur Sdn Bhd  RM   410.00
Matches
4
Rules run
1
Characters out
207

How it works

  1. 1

    Type what you are looking for

    Literal mode is the default and every character means itself: “RM 1,240.00” finds that exact text, brackets are brackets, and a full stop does not match every character. That is what most people want, and it is the default because a search string accidentally read as a pattern gives a wrong answer without ever showing an error.

  2. 2

    Look at the preview before you commit

    The preview panel shows your original text with every match highlighted, so you can see how many there are and where — including the ones you did not intend. Matches are drawn as real elements built from your text, never as markup injected into this page, so nothing you paste can change how this page behaves.

  3. 3

    Switch on regex, then press Run

    Regex mode does not run on every keystroke, and it does not run on this page’s own thread. Your pattern, the flags and your text are handed to a Web Worker, and the page starts a 1.5-second clock; if the worker has not answered by then it is terminated outright and you get a written explanation rather than a dead tab. Half a pattern is usually an error too — “(” and “[” are unterminated until you finish typing them — so Run also means the moment it happens is your decision. Literal mode stays live as you type, because escaped literal text cannot backtrack.

  4. 4

    Keep part of what you matched with $1

    Round brackets remember what they matched and $1, $2 and so on put it back. Find (\w+), (\w+) and replace with $2 $1 to turn “Lim, Ahmad” into “Ahmad Lim”. $& is the whole match, and $$ is how you write one dollar sign. Whole word is a literal-mode control only, and the fourth question explains why that is not an oversight.

  5. 5

    Add more rules and run them in order

    Several find-and-replace pairs, applied top to bottom, each one working on the output of the one above it. Move them, duplicate them, remove them. Each rule reports its own match count, so a rule that quietly matched nothing is visible instead of being averaged into a total.

Frequently asked questions

What happens if I write a pattern that never finishes?

You get a sentence, and the tab keeps working. Some patterns are not slow but exponential: (a+)+b against a run of a characters with no b at the end makes the engine try every way of dividing that run between the two quantifiers, and thirty characters is already more than a billion attempts. A regular expression running on a page’s own thread cannot be interrupted — no timer fires, no error is thrown, control never comes back, and an input limit or a match limit never gets the chance to run. So regex mode here does not run on this page’s thread. The pattern, the flags and your text go to a Web Worker, the page starts a 1.5-second clock, and if the worker has not answered by then the page calls terminate() on it and tells you the pattern was too expensive, naming catastrophic backtracking as the likely cause. Terminating a worker is the only thing in a browser that reliably stops a running regular expression. Your text is untouched and still in the box. Literal mode never needs any of this, because a fully escaped literal pattern cannot backtrack.

My pattern says “not valid”. What do I do?

The sentence under the box is the browser’s own message and it usually names the problem. Three catch nearly everyone: “[” opens a character class that has to be closed with “]”; “(” opens a group that has to be closed with “)”; and a “*” or “+” at the very start has nothing in front of it to repeat. If you want one of . * + ? ^ $ { } ( ) | [ ] \ to mean itself, put a backslash in front of it — or switch regex off, where every character already means itself and nothing has to be escaped.

How do capture groups and $1 work?

Round brackets in the pattern remember the text they matched, and $1, $2 and so on write it back out in the replacement. To swap “Lim, Ahmad” into “Ahmad Lim”, find (\w+), (\w+) and replace with $2 $1. $& stands for the whole match, so replacing with [$&] wraps every match in square brackets, and $$ produces one literal dollar sign — which matters on this page, because the sample text is full of currency. Paste those two names into the box above and watch the preview highlight the two captured runs before you press anything.

Why is Whole word switched off in regex mode?

Two reasons. Wrapping your pattern in a boundary group would renumber your capture groups, so $1 would silently stop meaning what you wrote — a bug that produces plausible wrong output rather than an error. And in regex mode you already have \b, alternation and lookahead to describe exactly the boundary you want. There is a third thing worth knowing: \b in JavaScript is defined over [A-Za-z0-9_] only, so it is wrong the moment an accented letter is involved. /\bcafé\b/.test("café") is false, which you can check in a console in one line. The Whole word switch in literal mode is built on \p{L} and \p{N} instead, so café and Müller behave the way you would expect.

What do the i, m, s and u flags do?

i ignores case. m makes ^ and $ match at the start and end of every line instead of the whole text, which is what you want for anything line-oriented. s makes . match a line break, which it otherwise never does — this is the flag people are missing when a pattern works within one line and returns nothing across two. u turns on Unicode mode, and it changes meaning rather than adding it: \p{L} means “any letter” only when u is on, and without it \p is just the letter p. g is always on here, because replacing only the first match is not what a Replace all should do.

I ran the same replacement twice and got different answers. Why?

On a page that reuses one regular expression object, that is exactly what happens: a /g regex carries a lastIndex from one call to the next, so the second call starts searching from where the first one stopped. It is a one-line demonstration — const re = /a/g; re.test("a") is true, and running re.test("a") again is false. This page builds a fresh RegExp for every run and for every rule, so the answer never depends on what you did before. If a result really does change here, it is because a rule earlier in your list changed the text that the later rule sees.

Can I match across two lines?

Yes, but not with a dot on its own. “.” matches anything except a line break, which is why a pattern that works inside one line finds nothing across two. Turn on the s flag and “.” includes line breaks. To match the break itself, write \n — or \r?\n if the text might have come from Windows, where a line ends with two characters rather than one. And if you want ^ and $ to mean the start and end of a line rather than of the whole text, that is the m flag, not s.

What is the multi-rule mode actually for?

Applying a fixed list of substitutions in one pass: renaming a set of terms across a document, converting a column of codes, normalising the several spellings a form has collected. Every rule runs over the output of the rule above it, which is the point and also the one trap. Replace cat with dog, then dog with bird, and you finish with no cats and no dogs — because by the time the second rule runs, the cats have already become dogs. Order the list so that nothing you produce is something a later rule is hunting for, or route the risky one through a placeholder string that appears nowhere else.

Where does the text I paste here go?

Nowhere. Matching and replacing both run in JavaScript this page has already loaded, there is no upload, and nothing is written to localStorage — reload and the box is empty. It is worth stating plainly given what gets pasted into a find-and-replace: log extracts, configuration files, SQL dumps and CSV exports, which routinely carry names, addresses, internal hostnames and keys.