Regex Replace & Extract
Run your own pattern over a whole body of text — replace across it, extract every match, or keep only matching lines, entirely on this device.
Rewrite every match through a replacement template.
In Replace mode, the first matches and their replacements are previewed here.
Pulling every email, URL or phone number out of text has a ready-made tool — /extract-emails — this page is for your own pattern over your own text. Open the email, URL and phone extractor
Press ? for shortcuts
Do it offline:$ perl -pe 's/(\w+)@(\w+)/$2:$1/g' file.txt
How to use it
- Choose the mode first — replace rewrites the body, extract lists the matches, keep-lines filters whole lines.
- Type the pattern without slashes and tick flags; g is what makes a replace apply to every match rather than the first.
- Paste the body, or drop a .txt or .log file — the file is read by the browser and never sent anywhere.
- In extract mode add a template such as $2 <- $1 to reshape each row, then dedupe, count or sort those rows.
- Copy the result, download it as .txt, or share the whole setup as a link; credential-shaped input is left out of that link.
One pattern, three jobs over the same body of text: rewrite every match in place, pull each match out as its own row, or keep only the lines a match touches. The work happens in a worker on this device, so a pasted log stays here. Panes hold their size in every state, whether the answer is two rows or two hundred thousand.
Examples
from=deploy@build.internal to=oncall@ops.example
from=cron@build.internal to=oncall@ops.examplefrom=deploy at build.internal to=oncall at ops.example
from=cron at build.internal to=oncall at ops.exampleNamed captures read back by name: $<u> at $<d> rewrites all four addresses in one pass, and the chip counts four replacements. The artifact is what String.prototype.replace returns in your own console, character for character.
Ada ada@example.com
Ops noreply@ithomia.devexample.com <- ada
ithomia.dev <- noreplyExtract mode emits one row per match, and the template swaps the two groups before the rows are deduped and sorted. Numbered tokens work in any mode; $<name> needs a pattern that actually names a group, or it stays on the page as literal text.
DEBUG cache warm
INFO ready
DEBUG flush
ERROR disk fullINFO ready
DEBUG flush
ERROR disk fullKeep-lines with the polarity inverted is grep -v — except that this run carries no g, so only the first hit is found and the second DEBUG line survives. The engine forwards the first-match-only chip rather than return a quietly wrong filter; ticking g drops both lines.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
Ascending is code-unit order, so Z lands before a
Rows are compared as UTF-16 code units, never through a locale collator: Zeta, Beta and alpha sort to Beta, Zeta, alpha. It is the one ordering that returns the same rows on every machine.
A match crossing a newline claims both lines
With the s flag a pattern can run past a line break. Keep-lines then holds, or drops, every line the span touches — not only the line it started on — and a zero-width hit still belongs to the line it sits at.
The shell equivalent is POSIX, not JavaScript
grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}' file.txt printed 2026-08-13 when it was run for this page on 13 August 2026. POSIX ERE has no \d, no lookbehind and no \p{…}, so a pattern that answers here can need rewriting there.
Past 100,000 matches the rows are the stored ones
That many match objects are kept; the total itself stays exact and a chip says which is which. Rows, dedupe tallies and line decisions then describe the stored matches only, while a replace result stays whole — one native pass produced it.
Common errors
unknown mode "REPLACE" — valid modes are replace, extract and filter-lines- A shared link was edited somewhere along the way. Unknown mode, sort and keep values are refused rather than rounded to a default, because a silent default answers a question nobody asked. Pick the mode again in the row above.
Template is larger than the 4096 character limit for this tool.- The row template is a formatting string, not a document; past 4,096 characters the run is refused with the bound printed, never trimmed to fit. Shorten it, or move the shaping into the pattern's capture groups.
replace mode needs a run executed with a replacement string — this run carries no replaced text- Replace mode reports the browser's own rewrite, so there is nothing to report until a replacement exists. An empty one is valid — it deletes every match — but it has to be part of the run.
Input is larger than the 16 MB limit for this tool. For bigger payloads use the CLI: perl -pe 's/(\w+)@(\w+)/$2:$1/g' file.txt- A refusal, not a trim: a partial pass would report counts for text never read. The one-liner handles any size, but perl is PCRE and grep -oE is POSIX ERE; neither is JavaScript, so \d, lookbehind and \p{…} can differ.
Stopped after 1 s — this pattern likely backtracks catastrophically on this input.- The watchdog destroyed the worker and a fresh one takes the next run, so the tab stays alive. Nested quantifiers over the same characters are the usual cause; the regex tester on this site is where that shape is explained and can be measured.
FAQ
What is the difference between the three modes?
Replace hands back the whole body with every match rewritten. Extract throws the body away and keeps a row per match, optionally reshaped by a template, deduped, counted and sorted. Keep-lines returns whole lines — the ones a match touches, or the ones it does not.
Which capture-group tokens can I use?
The replacement-string set JavaScript itself defines: $1 to $99, $<name>, $& for the whole match, $` and $' for the text either side, and $$ for a literal dollar. A group number above the pattern's count is printed literally, an unmatched group expands to nothing, and $<name> stays literal when the pattern names no groups at all — a chip says so when it happens.
Can I run this over a whole log file?
Up to 16 MB, by dropping the .txt or .log onto the input pane; reading it is a local file read, with no request in the path. Larger than that and the tool refuses with the bound and a command-line escape rather than working on a slice of your file.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Run the pattern now, skipping the debounce.
- ⌘/Ctrl + S
- Download the result as .txt (overrides the browser's save dialog).
- ⌘/Ctrl + C
- Copy the result pane while nothing is selected.
- ⌘/Ctrl + Shift + C
- Copy the result pane even with a selection active.
- t
- Cycle to the next theme.
- ? or ⌘/Ctrl + /
- Open the shortcut help overlay.
- Esc
- Dismiss the topmost overlay.