Vimで置換する方法 :%s///gの一括置換と5つの使い分け
Vimでファイル全体の文字列を一括置換するなら :%s/置換前/置換後/g です。先頭の % が「全行」、末尾の g が「1行に複数あっても全部」という意味で、:%s/foo/bar/g と打てばファイル中の foo がすべて bar に変わります。
置換の方法はこれだけではありません。今いる行の一部を書き換えるだけなら、置換モード・ビジュアルモード・オペレータという別の手があり、場面によって向き不向きがあります。この記事では、まず :s の書き方をひととおり押さえ、そのあと置換モード・ビジュアルモード・オペレータ・cgnを含めた5つの方法の使い分けを扱います。
目次(14項目)
| キー | これだけ覚える |
|---|---|
:%s/置換前/置換後/g | ファイル全体を一括置換 |
:%s/置換前/置換後/gc | 1件ずつ確認しながら置換 |
| R | 置換モード。同じ文字数の上書きに |
| ciw | 単語単位ですばやく書き換え |
| . | 直前の変更を繰り返す |
1. 置換コマンド(:s)で一括置換する
:[range]s[ubstitute]/{pattern}/{string}/[flags]
他のエディタでもおなじみの置換コマンドです。rangeを省略すると現在行だけが対象になり、%を付けるとファイル全体になります。末尾のgを付けないと、各行の最初の一致だけが置換されます。foo fooとfooの2行で試すと、:%s/foo/bar/はbar fooとbar、:%s/foo/bar/gはbar barとbarになりました。
:%s/foo/bar/g " ファイル全体を一括置換
:s/foo/bar/g " 今の行だけ
:5,10s/foo/bar/g " 5〜10行目だけ
:'<,'>s/foo/bar/g " ビジュアルモードで選んだ範囲だけ
範囲を絞りたいときは、行番号を数えるより、ビジュアルモードで選んでから:を押すほうが確実です。:'<,'>が自動で入るので、続けてs/foo/bar/gと打つだけで済みます。複数のファイルに同じ置換をかけるなら、引数リストと:argdoで対象のファイルを並べてから流します。
確認しながら置換する(c フラグ)
範囲を間違えて余計な行まで置換するのが心配なら、cフラグを付けます。一致するたびに置換するかどうかを聞かれるので、ここで押せるキーを知っておきます。
:%s/foo/bar/gc
| キー | 動作 |
|---|---|
| y | この箇所を置換する |
| n | この箇所をスキップする |
| a | 残り全部を置換する |
| q | ここで終了する |
| l | ここだけ置換して終了する |
途中まで y と n で判断して、あとは同じでよいと分かった時点で a を押す、という使い方ができます。q で抜けてもそこまでの置換は残るので、やり直したければ u を1回押します。
:%s/config/cfg/gc を実行したところ。1か所ごとに y n a q l で答える全行の行頭・行末に文字を足す
foo = 1 bar = 2 baz = 3
:%s/^/# /# foo = 1 # bar = 2 # baz = 3
置換前のパターンを行頭を表す^にすると、何も消さずに指定した文字列だけを挿入できます。行末を表す$なら:%s/$/;/で各行の末尾に;が付きます。コメントアウトしたい行をまとめて選んでから使えば一括コメントアウトに、SQLの各行にセミコロンやカンマを補いたいときにはこちら、という使い分けです。
パターンと置換後の書き方
\(...\)でくくった部分は、置換後の側で\1のように参照できます。マッチした中身を活かしたまま前後に文字を足したいときに使います。
:%s/\(\d\+\)/[\1]/g " x 12 y 3 → x [12] y [3]
:%s/\<foo\>/bar/g " 単語のfooだけ(foobarは対象外)
:%s/foo/bar/gi " 大文字小文字を区別しない
:%s/foo/bar/gI " 大文字小文字を区別する
\<と\>は単語の先頭と末尾の境界で、foobarの中のfooを巻き込みたくないときに付けます。iとIは'ignorecase'の設定をその置換だけ上書きするフラグで、ignorecaseを常時オンにしている人が厳密に区別したいときはIを使います。
パスを扱うときに / を区切りにすると、パターンの中の / をすべて打ち消すことになって読めなくなります。区切り文字は英数字とバックスラッシュ以外の記号から自由に選べるので、置換前後に出てこない記号を選びます。
:%s#/usr/local#/opt#g " # を区切りにする
:%s,../lib,./lib,g " , を区切りにする
改行を扱うときは、パターン側の \n が改行に一致し、置換後の側では \r が改行を意味します。この2つが逆なのが引っかかりやすいところです。
:%s/foo\nbar/foobar/ " 2行を1行にまとめる
:%s/,/\r/g " カンマで行を分ける
:%s/;\n/;/ " セミコロンの後ろの改行を消す
置換後に \n と書くとヌル文字が入ります。a,bに:s/,/\n/gをかけると、行は分かれずにa^@bになりました。改行を入れたいときは必ず \r です。行をつなぐだけなら J のほうが手軽なので、条件付きでつなぎたいときにこの書き方を使います。最短マッチのような込み入ったパターンは最短マッチの記事で扱っています。
同じ置換をもう一度かける(&)
置換コマンドは . では繰り返せません。代わりに & を押すと、直前の置換を今いる行にもう一度かけられます。
& " 直前の置換を今の行に(フラグは引き継がない)
:&& " フラグ込みで今の行に
:%&& " フラグ込みでファイル全体に
フラグを引き継がない違いは結果に出ます。1行目に:s/foo/X/gをかけたあと、foo fooの2行目で&を押すとX foo、:&&ならX Xでした。まず1行で試し、思ったとおりなら :%&& で全体に広げる、という進め方なら、失敗しても戻す範囲が小さくて済みます。
2. 置換モード(R)
R{変更後のテキスト}
対象の位置に移動してRを押すと置換モードに入り、上書きで文字を打ち込めます。初心者が最初に覚えやすい方法ですが、置換前後で文字数が変わる編集には向きません。
let value = 100;
let value = 200;
文字数が同じ書き換えに限定される点が弱点です。桁数が変わる書き換えでは、余分な文字が残ったり足りなくなったりします。
3. ビジュアルモード+オペレータ
v{範囲を選択}c
ビジュアルモードで範囲を選択してからcで変更します。矩形選択したいときはCtrl-vを使います。選択した範囲がそのまま見えるので直感的ですが、範囲指定のたびにカーソルを動かす手間があり、同じ操作を繰り返す用途にはやや不向きです。
4. オペレータ+モーション/テキストオブジェクト
cw " 単語の頭にいる場合
ciw " 単語のどこにいてもよい場合
移動を最小限にして、範囲指定と変更を1つのコマンドで済ませる方法です。tやfで素早く目的の位置まで移動し、そこからcwやciwで書き換える、という流れが定番になります。cwとciwの使い分けはcwとciwの違いで詳しく扱っています。
同じ書き換えを繰り返すなら . と組み合わせる
どの方法を選んだ場合でも、同じ変更を別の場所にも繰り返したいなら.(ドットコマンド)が効きます。ciwで単語を書き換えたあと、次の対象へtやfで移動して.を押すだけで、直前と同じ変更を再現できます。置換コマンドの:sはパターンマッチなので繰り返しに強いですが、単発の書き換えを複数箇所に展開したいときはciw系と.の組み合わせのほうが手数が少ないことが多くあります。
5つ目の方法:gn で「検索して書き換える」
もう1つ、gn という範囲指定があります。直前に検索した語にマッチする範囲を選ぶモーションで、cgn と打つと「次の該当箇所を書き換える」になります。
手元のVim 9.1.1752で /bar と検索してから cgn で打ち直すと、その語だけが置き換わりました。ここまでは ciw と変わりませんが、続けて . を押すと「次の該当箇所へ飛んで、同じ書き換えをする」まで一度に実行されます。
/bar<Enter> " 書き換えたい語を検索する
cgnBAR<Esc> " 1か所目を書き換える
. " 次の該当箇所へ飛んで同じ書き換え
n. " 1つ飛ばしたいときは n で送る
置き換えたい箇所とそのままにしたい箇所が混ざっているとき、これが最も手数が少なくなります。飛ばしたい箇所では n を押すだけで済むためです。
どれを選べばいいか
| 状況 | おすすめ |
|---|---|
| ファイル全体・複数行の一括置換 | 置換コマンド(:%s///g) |
| 置換するかを1か所ずつ判断したい | cフラグかcgn+. |
| 同じ文字数で単純に上書き | 置換モード(R) |
| 選択範囲を目で確認しながら変更 | ビジュアルモード |
| 単語単位の書き換えを素早く | オペレータ+モーション |
:%s/置換前/置換後/g、不安ならgcで確認しながら進めます。行の一部を書き換えるだけなら、単語単位はオペレータ+モーション、それ以外は:s、くらいの基準で十分実用になります。
最初は:sだけで何でも済ませていましたが、単語単位の書き換えが多い作業では明らかにオペレータ+モーションのほうが手数が少なくなりました。逆にファイル全体にまたがる置換でciwを繰り返すのは非効率です。複数行にまたがるSQLの末尾にカンマを付け忘れて何度もやり直した経験から、:%s/$/,/で行末挿入をまとめて済ませる癖もつきました。範囲を間違えて余計な行まで置換してしまったこともあり、それ以来ファイル全体に影響する置換はcフラグを付けて確認するようにしています。
取り消しの単位で選ぶ
どの方法を選ぶかは、失敗したときにどこまで戻したいかでも変わります。:s はコマンド1回ぶんがまとめて1つの変更になるので、u を1回押せば全部戻ります。
いっぽう cgn と . の組み合わせは1か所ずつが別々の変更なので、u を押した回数だけ戻ります。直前の1か所だけ取り消したいならこちら、全部やり直したいなら :s のほうが扱いやすい、という違いになります。
まとめ
一括置換は:%s/置換前/置換後/gで、範囲は%・行番号・ビジュアル選択の'<,'>、確認はc、行頭と行末への挿入は^と$で指定します。行の一部を書き換えるだけなら1つに絞る必要はなく、文字数が同じならR、単語単位ならオペレータ+モーション、混ざった箇所を選びながらならcgn、と場面で切り替えられるようになると編集速度が安定します。大文字小文字をまとめて変える\Uや\uは大文字・小文字の変換で扱っています。
ここで扱ったキーは、ブラウザ上で動くVim道場のまとめて置換するでそのまま試せます。インストールもログインも要りません。