直前の検索キーワードをそのまま変更するcgn/cgN
/urlで検索してから、やっぱりその「url」を別の単語に変えたくなりました。わざわざciwでカーソル位置の単語を変更しなくても、直前の検索キーワードをそのまま対象にして変更に入れるコマンドがあります。
検証環境:macOS + Vim 9.1.1752。.の繰り返し、nで飛ばしたときの結果、*直後のカーソル位置は、実際に操作して確かめたものです。
| キー | これだけ覚える |
|---|---|
| cgn | 次の検索マッチを変更 |
| cgN | 前の検索マッチを変更 |
| n . | 次のマッチへ移動して同じ変更を繰り返す |
| dgn / ygn | 次のマッチを削除 / ヤンク |
基本の使い方
cgn " 次の検索マッチを変更
cgN " 前の検索マッチを変更
cgnは変更のオペレータcと、検索結果へのビジュアル選択を兼ねたモーションgnの組み合わせです。直前に/や*で検索したパターンに対して、次にマッチする箇所を自動的に選択し、そのまま変更モードに入ります。
gnは他のオペレータとも組み合わせられる
gn自体はビジュアルモードでの選択としても使えるモーションなので、cgnだけでなくdgn(次のマッチを削除)やygn(次のマッチをヤンク)のように、他のオペレータと組み合わせても同じ発想で使えます。手元でoldを検索した状態からdgnを実行すると、カーソル以降の最初のoldだけが消えました。逆向きに探すgNも同じ要領で、cgNならカーソルより手前のマッチが対象になります。cとの組み合わせが特によく使われるのは、検索して見つけた文字列をその場で書き換えたい場面が単純に多いためです。
置換コマンドとの違い
:%s/old/new/gのような一括置換と違い、cgnは1件ずつ手動で確認しながら進められます。全部を機械的に変えたいわけではなく、文脈を見ながら変更するかどうかを都度判断したい場合に向いています。
.コマンドと組み合わせて連続変更する
/old<Enter> " 検索
cgnnew<Esc> " 最初の1件を変更
. " 次のマッチへ進んで同じ変更
. " さらに次へ
ここがcgnの一番おいしいところです。.を押すだけで、次のマッチまで移動して同じ変更が入ります。nで送ってから.を押す必要はありません。gnが「カーソル位置以降の最初のマッチ」を選ぶモーションなので、繰り返しのたびに検索が動くためです。
4行すべてにoldがあるバッファで手元のVim 9.1を使い、cgnのあと.を2回押した結果です。
| 操作 | バッファの状態 |
|---|---|
| cgnで1件目を変更 | NEW one / old two / old three / old four |
| . | NEW one / NEW two / old three / old four |
| . | NEW one / NEW two / NEW three / old four |
飛ばしたいときだけnを使う
ではnはいつ使うのかというと、変更したくないマッチを飛ばすときです。nを押すとカーソルが次のマッチへ移り、その状態で.を押すとそこが変更対象になります。つまり1件飛ばしたいならnを2回押してから.です。
NEW one
old two
old three
NEW one
old two
NEW three
手元でも2行目はoldのまま、3行目だけが変わりました。「全部変える」なら.の連打、「ここは残す」ならnを1回多く押す、という覚え方になります。
要点:検索した単語をそのまま変更したいならcgnを使います。繰り返しは.だけで進み、飛ばしたいときにだけnを挟みます。
*で検索したときは1件目に注意
カーソル下の単語を検索する*から始める場合、1つ落とし穴があります。*はカーソルを次のマッチへ移動させるので、そのままcgnすると最初の1件が変更されずに残ります。手元で3か所にfooがあるバッファの1行目で*を押すと、カーソルは2行目に移り、続けてcgnしたときに変わったのも2行目でした。
1件目から変更したいなら、*のあとにNを押して元の位置へ戻してからcgnを始めます。
変数名の一括置換をしたいが、一部だけは別の理由で変えたくない、という場面で:s///gは使いにくいと感じていました。cgnと.の繰り返しを覚えてからは、1件ずつ目で見て判断しながら変更を進められるようになり、置換コマンドのcフラグで確認するより手に馴染む方法として定着しました。
マクロと組み合わせるとさらに強力
cgnによる1件の変更をマクロとして記録しておけば、以降は@aを連打するだけで残りのマッチも次々に処理できます。1件ごとに文脈を見て判断したいが、判断のパターンがだいたい決まっているなら、マクロ化して手数をさらに減らすと便利です。判断を伴う変更と機械的な変更が混在する場合は、途中でマクロを止めてcgn単体に戻せる柔軟さも覚えておくと安心です。
まとめ
cgnは検索と変更をつなぐ橋渡し的なコマンドで、機械的な一括置換より柔軟に使えます。似た発想のオペレータ+検索モーションもあわせて覚えておくと、検索を軸にした編集の幅が広がります。