Vimでオペレータ+検索モーションを使う(c/ d/ y/)
今いる場所から数行先にある特定のキーワードまで、まとめて削除したいことがあります。行数を数えてd5jのように指定するより、検索パターンをそのままモーションとして使ったほうが速くて確実です。
目次(9項目)
| キー | これだけ覚える |
|---|---|
| d/{キーワード}Enter | 次にヒットする直前まで削除 |
| c/ / y/ | 同じ範囲を変更 / ヤンク |
| d?{キーワード}Enter | 上方向へ検索して削除 |
基本の書き方
c/{検索キーワード}<Enter> " 変更
d/{検索キーワード}<Enter> " 削除
y/{検索キーワード}<Enter> " ヤンク
検索コマンド/自体がモーションとして扱われるため、オペレータのあとに検索パターンを続けてEnterを押すだけで、今のカーソル位置から検索でヒットした位置の直前までが操作の対象になります。複数行にまたがっていても関係なく、1コマンドで範囲を指定できます。
1単語ではなく検索パターンだから強力
d3wのような数を数える移動と違い、対象範囲を「次にこの文字列が現れるまで」という条件で指定できるのが最大の利点です。行数や単語数を数える必要がなく、目的の文字列さえ分かっていれば、そこまでの距離がどれだけ離れていても正確に範囲を指定できます。
config.enable = true ^ カーソル debug: true TODO: remove flag
TODO: remove flag
カーソルより下にある2行がまとめて消え、検索にヒットした行はそのまま残ります。行数を数える必要はなく、「TODO」という文字列さえ分かっていれば範囲が決まります。
逆方向にも使える
c?{検索キーワード}<Enter> " 上方向へ検索して変更
d?{検索キーワード}<Enter> " 上方向へ検索して削除
/の代わりに?を使えば、カーソルより前の方向へ検索してその範囲を対象にできます。前の方に出てくる区切り文字までさかのぼって削除したいときなどに使えます。
使いどころ
括弧の中や引用符の中のようにテキストオブジェクトで簡単に範囲指定できる場面では、わざわざこの方法を使う必要はありません。真価を発揮するのは、テキストオブジェクトでは指定しにくい「特定のキーワードが現れるまで」というような、構造に頼らない範囲指定をしたいときです。ログファイルの中で次のエラーメッセージが出るまでの行をまとめて確認したい、といった場面に向いています。
長いログの中から次のセクション区切りの文字列までをまとめて削除したい場面で、行数を数えてdを打つよりd/で区切り文字列を指定したほうが圧倒的に速く、しかも数え間違いによる事故もなくなりました。慣れると、まず「どこまで操作したいか」を文字列で考える癖がつきます。逆方向の?を使い忘れて、遠回りにggから検索し直したこともあるので、両方向あることは意識しておくと安心です。今では作業の前に「上に戻るか下に進むか」を一瞬考えてから打つ癖がついています。
検索モーションは手前で止まる
d/TODO と打つと、TODO の直前までが消えて TODO 自体は残ります。検索モーションが exclusive(見つかった位置を含まない)と決まっているためで、他のエディタの「〜まで削除」と食い違いやすいところです。
見つかった語も含めて消したいときは、検索パターンの後ろにオフセットを付けます。/TODO/e は語の末尾に止まるという指定なので、d/TODO/e なら TODO ごと消えます。
d/TODO<Enter> " TODO の手前まで消す
d/TODO/e<Enter> " TODO を含めて消す
d/TODO/e+1<Enter> " TODO の次の1文字まで消す
オフセットは検索そのものにも効くので、/TODO/e だけを打てばカーソルが語の末尾に止まります。範囲指定と移動で同じ書き方が使えるということです。
見つからなかったときは何も起きない
検索した語がファイルの中に無ければ、削除も書き換えも実行されません。エラーは出ますが、バッファは無傷です。範囲が読み切れないときに d/ を試しても、当たらなければ壊れないという安心感があります。
逆に、当たったけれど思っていた場所ではなかった、という失敗はあり得ます。範囲が広い操作をする前に、同じパターンを / だけで検索して着地点を目で見ておくと確実です。incsearch を有効にしておけば、打っている途中から飛び先が見えます。
折り返しに注意する
Vimの検索は既定でファイルの末尾まで行くと先頭に戻ります。オペレータと組み合わせたときにこれが起きると、カーソルより前の位置が範囲の端になり、意図しない方向の範囲が消えることになります。
下方向にだけ効かせたいなら set nowrapscan を設定します。折り返さなくなるので、見つからなければ何も起きません。ファイル全体を対象にした一括処理には置換コマンドのほうが向くので、d/ は「いま見えている範囲の少し先まで」を狙う道具だと考えると使い分けが決まります。
まとめ
検索パターンをモーションとして使うオペレータ+検索は、距離や行数を意識せずに範囲指定できる強力な手段です。cgnによる「検索してすぐ変更」という近い発想のコマンドは別記事で扱っています。検索をモーションにするのと同じ感覚で、行内の1文字を狙うfやtもオペレータの後ろに置けます。短い距離ならこちらのほうが打鍵数は少なくて済みます。