Wai Hon's Blog

Options to Replace String in Large Scale

2023-10-25 #engineering #emacs

10 years ago, when I became a software engineer, my mentor showed me how to replace all occurrences of a string (or a regex) under a large codebase effectively with a tool called codemod. It turned out to be one of the most useful text-editing techniques in my next 10 years, saving me many hours of “find and replace” manually.

Over time, I discovered additional options for different use cases. Here they are.

For Simple Replacement - sed

sed is my favorite for simple cases because it comes pre-installed in most operating systems.

# replace all instances of `foo` (regex) with `bar` (regex) in a file
sed -i "s/foo/bar/g" path/to/file

# replace all instances of `foo` (regex) with `bar` (regex) found by `find`
find . -name '*.cpp' | xargs sed -i "s/foo/bar/g"

# replace all instances of `foo` (regex) with `bar` (regex) in modified files under git
git diff --name-only | xargs sed -i "s/foo/bar/g"

If I encounter a performance issue, I will switch to fastmod.

For Very Large Code Base - fastmod

fastmod is a fast partial replacement for codemod. It is written in Rust and is designed for large-scale codebase refactoring.

# replace a regex pattern in specific files or directories:
fastmod 'foo' 'bar' -- {{path/to/file path/to/directory ...}}

To install, run cargo install fastmod, assume you have Rust’s Cargo installed.

For more use cases, see tldr:fastmod.

For Simple Replacement in Emacs - dired

As an Emacser, I must also provide a way to achieve this in Emacs.

  1. M-x dired
  2. Mark the required files and directories (m to select, t to toggle all)
  3. Press Q (dired-do-find-regexp-and-replace) to replace string by regex
    1. Press y to accept.
    2. Press ! to accept all.

For Interactive Replacement in Emacs - wgrep

wgrep stands for “Writable Grep Buffer”. It is a very flexible interactive replacement in Emacs. It gathers all occurrences in a buffer and then you can use whatever you want edit them.

  1. Search with counsel, e.g., counsel-rg
  2. C-c C-o (ivy-occur)
  3. C-x C-q (ivy-wgrep-change-to-wgrep-mode)
  4. Edit (e.g., replace-regex)
  5. C-c C-c (commit the changes)

For more details on this method, see:

For Interactive Replacement in Emacs Project - project-query-replace-regex

project.el provides a command called project-query-replace-regex (default keybinding: C-x p r) that allows you to interactively replace a regex pattern within a project.

Epilogue

In most cases, I prefer sed and fastmod since they allow me to do it in a single command, which makes it easier to iterate the desired command (execute and revert for the right “foo” and “bar”).