Vimのcwとdwの違い 末尾の空白の扱いが違う理由
cwとdwは、どちらも「単語」を対象にしたオペレータ+モーションですが、実行結果を見比べると空白の扱いが違うことに気づきます。単なる気のせいではなく、Vimのヘルプにも明記されている仕様です。
| キー | これだけ覚える |
|---|---|
| cw | 単語を変更。末尾の空白は残る(インサートモードへ) |
| dw | 単語を削除。末尾の空白も消える(ノーマルモードのまま) |
| ce | 単語頭ではcwと同じ結果になる |
2つの違い
空白は目に見えないので、ここでは·で表します。hello·worldのhにカーソルを置いた状態で、それぞれを実行するとこうなります。
| cw | dw | |
|---|---|---|
| 消える範囲 | hello(5文字) |
hello·(6文字。空白ごと) |
| 直後の行 | ·world |
world |
| 実行後のモード | インサートモード | ノーマルモード |
続けてbyeと打つと |
bye·world |
byeworld |
いちばん下の行が実用上の違いです。cwは空白を残したまま挿入モードに入るので、そのまま新しい単語を打てばbye·worldと正しく区切られます。dwは空白ごと消すため、同じ位置にiで打つとbyeworldと単語がくっついてしまいます。cwが空白を残す仕様なのは、単語の「置き換え」を打ち直しなしで完結させるためです。
モードが分かれるのはcとdというオペレータ自体の性質によります。変更するなら次に入力する作業へ移りたいし、削除するなら移動したいだけ、というユーザーの自然な動作を反映しています。
Vim公式ヘルプが「バグかもしれない」と書いている理由
興味深いのは、このcwの特別扱いについて、Vimのヘルプ自体が「Vi本来の挙動は多分バグ」だと書いていることです。もともとのviでは、単語の後に続く空白の上でcwを実行すると最初の空白だけを変更してしまう仕様でした。dwは空白をすべて削除するのにcwだけ挙動が違う、という非対称さが元々の由来で、Vimではこれを踏襲しつつ「単語の変更として自然になるよう」空白を残す形に調整されています。
ceとの違いにも触れておく
ヘルプにあるとおり、cwは単語頭にカーソルがあるときce(単語末尾までを変更)とほぼ同じ動作になります。両者が完全に同じというわけではありませんが、実用上は「cwは事実上ceとして振る舞う」と理解しておくと、なぜ空白が残るのかが腑に落ちやすくなります。ceはそもそも「単語の末尾まで」を対象にする設計なので、末尾の空白を含まないのは自然な結果です。
日本語の文章でも使えるが癖がある
cw/dwは日本語にも一応反応しますが、英語の「単語」とは判定基準が異なります。全角スペースと半角スペースは同じ扱いになり、ひらがな・カタカナ・漢字・記号がそれぞれ連続する範囲を「単語」とみなします。文法上の単語区切りとは無関係なので、送り仮名だけを対象にするような細かい操作には向きません。
最初は「なぜdwとcwで空白の扱いが違うんだ」と単なるバグだと思っていましたが、ヘルプを読んで意図的な調整だと知ってから納得できました。理屈が分かると、次からは動作を覚え直す必要がなくなるのがVimらしいところだと思います。
まとめ
cwとdwには、モードの違いに加えて、末尾の空白の扱いという非対称な仕様があります。単語頭以外にカーソルがあるときの挙動の違いはcwとciwの違いで扱っています。