Skip to content

About

Find and replace text using regular expressions with real-time preview and match highlighting for Obsidian

Resources

Contributing

Stars

13 stars

Watchers

0 watching

Forks

Repository files navigation

Obsidian Regex Replace

Safely clean up Markdown in Obsidian with live previews, match highlighting, and reusable multi-step pipelines.

Obsidian plugin License Buy Me a Coffee

Preview every change before it touches your note. Run a one-off replacement or save a complete cleanup workflow for PDFs, AI-generated text, and Markdown.

Regex replace dialog showing a pattern, its match count, and a before/after preview with every match highlighted

Why Regex Replace?

Capability Obsidian's built-in replace Regex Replace
Regular expressions and capture groups — ✓
Before/after preview — ✓
Match highlighting — ✓
Replace within a selection — ✓
Replace across the whole vault — ✓
Reusable multi-step cleanup pipelines — ✓
Import regex-pipeline rulesets — ✓

Everything runs locally in your vault. The plugin does not send note content to external services.

Features

  • Regular Expression Support: Full JavaScript regex syntax including capture groups ($1, $2, etc.)
  • Case Operators: \u, \l, \U, \L and \E in the replacement, as in sed and VS Code
  • Real-time Preview: See matches highlighted before replacing
  • Match Highlighting: Visual diff showing before/after changes
  • Regex Flags: Toggle global (g), case-insensitive (i), and multiline (m) flags
  • Selection Mode: Replace only within selected text
  • Pattern History: Save and reuse recent search patterns
  • Pipeline Rulesets: Save reusable multi-step rulesets and apply them in sequence, with a step-by-step preview — and import existing regex-pipeline rulesets
  • Vault-wide Replace: Replace across every note, or one folder — review the matches, pick the files, and undo the whole run afterwards
  • Selection-only Rulesets: Mark a ruleset as selection-only and it stays that way — hotkeys included — instead of resetting every time the dialog opens
  • Dark/Light Theme: Optimized for both Obsidian themes

Popular cleanup recipes

Copy a search and replacement into Regex Replace, review the preview, and apply it only when the result is correct for your note.

Cleanup Search Replace Flags
Collapse repeated spaces {2,} g
Remove trailing whitespace [ \t]+$ (empty) gm
Collapse 3+ blank lines \n{3,} \n\n g
Change H2 headings to H3 ^## ### gm
Convert ISO dates to day/month/year (\d{4})-(\d{2})-(\d{2}) $3/$2/$1 g
Remove Markdown bold markers \*\*([^*]+)\*\* $1 g
Convert simple wiki links to Markdown links `[[([^] ]+)]]` [$1]($1.md)

Caution

A regular expression can match more text than intended. Check the highlighted preview before applying a replacement, especially with broad patterns.

Installation

Requires Obsidian 1.13.0 or later — the settings tab uses the declarative settings API introduced in that version, so its settings appear in Obsidian's settings search. Version 1.1.5 remains available for older releases.

From Obsidian Community Plugins (Recommended)

  1. Open Settings → Community plugins in Obsidian.
  2. Select Browse and search for Regex Replace.
  3. Select Install, then Enable.

Manual Installation

  1. Download main.js, manifest.json, and styles.css from the latest release
  2. Create a folder: <YourVault>/.obsidian/plugins/regex-replace/
  3. Copy the downloaded files into this folder
  4. Reload Obsidian and enable the plugin in Settings → Community Plugins

Usage

Open the replace dialog

  • Hotkey: Cmd/Ctrl + Shift + H
  • Command Palette: Cmd/Ctrl + P → "Open Regex Replace"

Preview before replacing

+--------------------------------------+
| Search pattern:  \b(world)\b         |
| Replace with:    WORLD               |
|                                      |
| Flags: [x] g   [ ] i   [ ] m         |
|        [ ] Replace in selection only |
|                                      |
| 2 match(es) found                    |
|                                      |
| Preview                              |
|  Before: Hello world, hello world    |
|  After:  Hello WORLD, hello WORLD    |
|                                      |
|  2 match(es):                        |
|   - "world" -> "WORLD"               |
|                                      |
|           [ Replace all ] [ Cancel ] |
+--------------------------------------+

Before highlights every match in yellow, and After highlights each replacement in green. Previously used patterns reappear in a Recent patterns dropdown below the preview.

Regex examples

Use Case Search Pattern Replace Result
Find numbers \d+ [NUM] abc123 → abc[NUM]
Date format (\d{4})-(\d{2})-(\d{2}) $3/$2/$1 2024-12-08 → 08/12/2024
Remove extra spaces \s+ Multiple spaces → single
Wiki to MD link \[\[(.+?)\]\] [$1]($1.md) [[Note]] → [Note](Note.md)
Header H2 → H3 ^## ### ## Title → ### Title
Remove bold \*\*(.+?)\*\* $1 **bold** → bold
Extract link text \[(.+?)\]\((.+?)\) $1: $2 [text](url) → text: url

Flags

Flag Name Description
g Global Replace all matches (not just the first)
i Ignore Case Case-insensitive matching
m Multiline ^ and $ match line starts/ends

Capture groups

Use parentheses () to capture groups and reference them with $1, $2, etc.:

Search:  (\w+)@(\w+)\.com
Replace: User: $1, Domain: $2

Input:   test@example.com
Output:  User: test, Domain: example

Changing case in the replacement

The replacement understands the same case operators as sed, vim and VS Code. \U and \L recase everything that follows until \E; \u and \l touch only the next character.

Search:  (- )([a-z])
Replace: $1\u$2
Flags:   gm

Input:   - element 1
Output:  - Element 1
Operator Effect
\u Uppercase the next character
\l Lowercase the next character
\U Uppercase everything until \E
\L Lowercase everything until \E
\E End the \U / \L span

Pipeline Rulesets

A ruleset is a named list of find/replace rules applied in sequence — each rule operates on the previous rule's output. Useful for repeatable, multi-step cleanups (e.g. normalize headers, then collapse whitespace, then fix links).

Defining a ruleset

In Settings → Regex Replace → Pipeline rulesets, click Add ruleset, name it, and write rules using regex-pipeline syntax (one rule per block):

"SEARCH"->"REPLACE"
"\s+"->" "
"##\s"gm->"### "
  • Inline flags follow the search quote (e.g. "foo"gi->"bar"); without them, gm is used.
  • Replacements may span multiple lines.

Applying a ruleset

  • Command Palette: "Apply ruleset (pipeline)" → pick a ruleset → review the step-by-step preview (match count per rule) → Apply pipeline.
  • Hotkey: each ruleset also gets its own Ruleset: <name> command, bindable to a hotkey or a Commander / Editing Toolbar button.
  • A rule with an invalid regex is skipped and reported, never aborting the whole run.

Running a ruleset on the selection only

Turn on Apply to selection only — either on the ruleset itself in settings, or with the checkbox in the pipeline dialog. Both write to the same stored value, so the choice survives the next open and applies to the Ruleset: <name> hotkey too.

When such a ruleset runs with nothing selected, it does nothing and shows a notice. It never falls back to the whole note, so a mis-fired hotkey cannot rewrite the file. Apply to selection only by default seeds the flag on newly added and imported rulesets, and rulesets saved before this option existed follow it until their own toggle is set.

Importing from regex-pipeline

Click Import from regex-pipeline to read every ruleset file in <vault>/.obsidian/regex-rulesets/ and convert it into a native ruleset.

Starter pipeline: clean pasted text

This ruleset removes trailing whitespace, reduces large blank gaps, and normalizes repeated spaces. Add it under Settings → Regex Replace → Pipeline rulesets, then preview it with Apply ruleset (pipeline).

"[ \\t]+$"gm->""
"\\n{3,}"g->"\\n\\n"
" {2,}"g->" "

Replace in Vault

Run Replace in vault from the command palette. Enter a pattern, flags, and a replacement, optionally limit it to a folder, then Scan vault.

The scan reads and matches in batches, so the progress count moves as it goes and you can cancel partway. When it finishes you get one row per file with a hit and its match count, all ticked. Untick the files you don't want; click a row to see that file's matches. Apply asks once more, naming how many files and roughly how long the write will take, and only replaces on the second click.

Replace in vault dialog after a scan, listing every matching file with its match count and a tickbox

Undoing

Undo last vault replace puts every file back. It keeps the last run only.

A file you edited after the replace is skipped rather than reverted, so an undo never overwrites work you did in between. The same check runs during apply: a file that changed between the scan and the write is skipped and reported.

Options

  • Skip frontmatter leaves the --- block alone. Read from Obsidian's own metadata, so a horizontal rule in the body is not mistaken for frontmatter.
  • Excluded paths (settings) is a glob list — Archive, Templates/**, **/*.excalidraw.md. A bare folder name covers everything under it. Hidden folders are already skipped. This is separate from Obsidian's own excluded-files setting, which plugins cannot read.
  • Match timeout (settings) is how long a batch may run before the worker is killed. A pattern that backtracks catastrophically — (\w+\s?)+$ and friends — cannot be interrupted on the thread running it, so matching happens in a worker the main thread can terminate. Raise the timeout for a big vault, not for a slow pattern.

On mobile

The vault commands were desktop-only in 1.2.2 while the worker that guards against a runaway pattern went unverified anywhere but the desktop. They run everywhere as of 1.3.0. The short version of why: backgrounding an app freezes the page, and a frozen page freezes its workers too, so the pattern stops when the watchdog does rather than burning on while nothing can kill it.

It is still the less-travelled path. If a scan ever seems to hang on a phone, lower Match timeout and report it.

Settings

Access via Settings → Regex Replace:

Setting Description Default
Default Flags Pre-selected regex flags g
Show Preview Display before/after preview true
History Limit Max saved patterns 10
Pipeline rulesets Add/edit/delete/import reusable rulesets —
Apply to selection only by default Seeds the flag on new and imported rulesets false
Vault scan: excluded paths Glob list of paths to skip when scanning the vault —
Vault scan: match timeout Milliseconds a batch may match before the worker is killed 2000
Vault replace: warn above File count past which the confirm step warns 1000

Development

# Clone the repository
git clone https://github.com/bongho/obsidian-regex-replace.git

# Install dependencies
npm install

# Build for development (watch mode)
npm run dev

# Build for production
npm run build

# Run tests
npx ts-node --transpile-only test.ts

Changelog

1.4.0

  • Case operators in the replacement. \u, \l, \U, \L and \E work the way they do in sed, vim and VS Code, so a pattern can change the case of what it captured instead of only moving it around (#24)
  • $` and $' now resolve in the preview. The preview dropped them silently, so it could disagree with what applying the replacement actually produced

1.3.1

  • Add a Buy Me a Coffee link (fundingUrl), so the plugin page in Obsidian shows a way to support the plugin
  • Update dependencies to clear two high-severity npm audit advisories (#22)
  • The test suite now imports src/ instead of keeping copies of it (#21)

1.3.0

  • Vault-wide replace runs on mobile. 1.2.2 held it back because the worker that stops a runaway pattern had never been exercised outside the desktop; it has now been traced far enough to lift the guard
  • The test suite tests the shipped code. test.ts copies the functions it exercises out of src/, and two of the copies had fallen years behind — preview and execute were still the versions from before replacement unescaping and before the fix for lookaround in the match list. npm test now fails when a copy drifts (#19)

1.2.2

  • Register the vault commands on desktop only. The protection against a runaway pattern is a worker the main thread can terminate, and that path has never run on a mobile device — isDesktopOnly stays false, so the rest of the plugin is unaffected (#18)
  • Document vault-wide replace in the README: usage, what undo restores, and the three vault settings
  • Say in the plugin description that vault-wide replace is desktop-only, so mobile users are not promised a command they will not see

1.2.1

  • Describe vault-wide replace in the plugin's own description — the directory and the plugin's detail page were still advertising the 1.1.x feature set (#16)
  • Run the test suite in CI. The workflow had called npm test since it was added with no script behind it, so the 68 cases had only ever run by hand (#17)

1.2.0

  • Replace across the whole vault or a folder with the new "Replace in vault" command (#15)
  • Scan streams as it reads, so progress is real and the run can be cancelled
  • Matching runs in a worker with a timeout, so a pattern that backtracks is stopped instead of freezing Obsidian
  • Selection is per file; skip frontmatter with a toggle; exclude paths with a glob list in settings
  • Undo a whole run with "Undo last vault replace" — files edited since the replace are left alone
  • Apply names the expected cost before you confirm, and warns past a configurable file count
  • Show the "select some text first" notice in the find/replace dialog even with the preview turned off (#14)

1.1.9

  • Stop "Replace in selection only" in the find/replace dialog from rewriting the whole note when nothing is selected (#11)

1.1.8

  • Store "apply to selection only" on the ruleset, so it survives reopening the dialog (#9)
  • Honour that flag in the Ruleset: <name> commands, which previously always rewrote the whole note
  • Refuse to run a selection-only ruleset with an empty selection instead of falling back to the whole note
  • Add a global "apply to selection only by default" setting that seeds new and imported rulesets
  • Run the plugin review's lint ruleset locally (eslint 10 + eslint-plugin-obsidianmd)

1.1.7

  • Drop the imperative display() fallback; the settings tab is declarative only
  • Raise minAppVersion to 1.13.0 — vaults below it stay on 1.1.5 via versions.json

1.1.6

  • Adopt the declarative settings API, so settings are indexed by Obsidian's settings search
  • Replace remaining document.createElement calls with Obsidian's createEl helpers
  • Tighten capture-group substitution types in src/engine.ts

1.1.5

  • Add dynamic ruleset commands for direct Obsidian invocation (Ruleset: )
  • Enable integration with Commander, Editing Toolbar, and macro plugins
  • Add maintainer info to README (Korean developer, AI researcher)

1.1.4

  • Reposition the plugin around safe previews and reusable cleanup pipelines
  • Add practical Markdown cleanup recipes and a built-in feature comparison
  • Align package metadata and documentation with the 0BSD license

1.1.0

  • Pipeline rulesets: save reusable multi-step rulesets, apply in sequence with step preview
  • Import rulesets from the regex-pipeline plugin
  • New command: "Apply ruleset (pipeline)"

1.0.0

  • Initial release
  • Regex find and replace with preview
  • Real-time match highlighting
  • Pattern history
  • Selection-only mode

License

0BSD License — see LICENSE for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support

If you find this plugin useful, consider:

  • Starring the repository on GitHub
  • Reporting issues or suggesting features
  • Contributing code improvements

About

Maintained by Bongho Lee, a Korean developer and AI researcher. Feedback, issues, and pull requests are welcome!


Made with ❤️ for the Obsidian community

About

Find and replace text using regular expressions with real-time preview and match highlighting for Obsidian

Resources

Contributing

Stars

13 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages