level 11

Search & Replace

The substitute command and regex for surgical edits.

:s is a tiny find-and-replace language living inside your editor. Full regular expressions, surgical control over scope, optional confirm-each-one prompting. When a rename is too irregular for n . and too big to do by hand, this is the tool. It looks cryptic for five minutes, then becomes the thing you miss in every editor that doesn’t have it.

The Substitute Command

:s/old/new/     → first match on the current line
:s/old/new/g    → all matches on the current line
:%s/old/new/g   → all matches in the whole file
:%s/old/new/gc  → file-wide, confirm each one

The g flag means “all on the line”; % means “the whole file”; c prompts for confirmation (y to replace, n to skip, q to quit).

Regex Patterns

\<word\>   → exact word (word boundaries)
\d\+       → one or more digits
^import    → lines starting with "import"
};$        → lines ending with "};"

Vim uses its own regex flavor: \+ means “one or more” (note the backslash), \d is a digit, \< and \> are word boundaries, ^ and $ anchor line start and end.

Heads up about the editor below. Real Vim and Neovim use the flavor above. The embedded editor here runs on CodeMirror, which uses JavaScript regular expressions — so in these exercises drop the backslash on quantifiers (\d+, not \d\+), use (...) for groups, and $1 $2 for backreferences. The :%s/old/new/flags structure is identical; only the pattern dialect changes. Where the real-Vim form differs, it’s noted inline.

\d+   (here)   →  \d\+   (real Vim)     one or more digits
(\w+) (here)   →  \(\w\+\) (real Vim)   a capture group
$1    (here)   →  \1     (real Vim)     reuse a captured group
&     (both)                            the whole match

Substitute on a line

  1. Type :s/cat/dog/ and Enter — only the first cat changes.
  2. Undo. Type :s/cat/dog/g — all of them on the line change.
  3. Undo. Type :s/the/a/g.
normalpress i to type · hjkl to move

goal Without g, only the first match per line changes.

File-wide substitution

  1. Type :%s/user/member/g — every user changes, including inside userId and getUser.
  2. Undo. Type :%s/User/Member/g — only the capitalized form changes.
normalpress i to type · hjkl to move

goal %s reaches every line; mind partial matches.

Confirm each replacement

  1. Type :%s/timeout/delay/gc.
  2. Press y to accept, n to skip, stepping through each prompt.
  3. Verify only the ones you accepted changed.
normalpress i to type · hjkl to move

goal Use the c flag for selective, not blind, replacement.

Regex patterns

  1. Replace user + digits with member: :%s/user\d+/member/g. (Real Vim: \d\+.)
  2. Undo. Replace lines starting with admin: :%s/^admin\d+/superuser/g.
  3. Undo. Replace the last word of each line: :%s/\w+$/ACTION/g.
normalpress i to type · hjkl to move

goal Use the \d digit class, anchors, and word boundaries to target precisely.

Real-world refactor

  1. Rename the class: :%s/UserProfile/MemberCard/g.
  2. Rename the field: :%s/userData/memberData/g.
  3. Rename the flag: :%s/userLoading/isLoading/g.
normalpress i to type · hjkl to move

goal One command per rename — the power of :s for large edits.

Capstone — capture groups and the whole-match &

A plain replace can only swap fixed text. Capture groups let you grab pieces of each match and rearrange them. Wrap part of the pattern in (...), then reference what you caught with $1, $2. & is the whole match.

  1. Flip every name to Last, First: :%s/(\w+) (\w+)/$2, $1/. Group 1 is the first name, group 2 the last; the replacement reorders them. (Real Vim: \(\w\+\) \(\w\+\) with \1 \2.)
  2. Undo with u. Now quote each entire line using the whole match: :%s/.+/"&"/& stands in for everything the pattern matched.
  3. Undo. Do both at once — reorder and quote: :%s/(\w+) (\w+)/"$2, $1"/.
normalpress i to type · hjkl to move

goal Reorder and wrap text by reusing what the pattern captured.