Vimのcwとdwの違い 末尾の空白の扱いが違う理由
cwとdwは、どちらも「単語」を対象にしたオペレータ+モーションですが、実行結果を見比べると空白の扱いが違うことに気づきます。単なる気のせいではなく、Vimのヘルプにも明記されている仕様です。
目次(9項目)
| キー | これだけ覚える |
|---|---|
| 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というオペレータ自体の性質によります。変更するなら次に入力する作業へ移りたいし、削除するなら移動したいだけ、というユーザーの自然な動作を反映しています。
hello の後ろの空白まで消えているVim公式ヘルプが「バグかもしれない」と書いている理由
興味深いのは、このcwの特別扱いについて、Vimのヘルプ自体が「Vi本来の挙動は多分バグ」だと書いていることです。もともとのviでは、単語の後に続く空白の上でcwを実行すると最初の空白だけを変更してしまう仕様でした。dwは空白をすべて削除するのにcwだけ挙動が違う、という非対称さが元々の由来で、Vimではこれを踏襲しつつ「単語の変更として自然になるよう」空白を残す形に調整されています。
ceとの違いにも触れておく
ヘルプにあるとおり、cwは単語頭にカーソルがあるときce(単語末尾までを変更)とほぼ同じ動作になります。両者が完全に同じというわけではありませんが、実用上は「cwは事実上ceとして振る舞う」と理解しておくと、なぜ空白が残るのかが腑に落ちやすくなります。ceはそもそも「単語の末尾まで」を対象にする設計なので、末尾の空白を含まないのは自然な結果です。
日本語の文章でも使えるが癖がある
cw/dwは日本語にも一応反応しますが、英語の「単語」とは判定基準が異なります。全角スペースと半角スペースは同じ扱いになり、ひらがな・カタカナ・漢字・記号がそれぞれ連続する範囲を「単語」とみなします。文法上の単語区切りとは無関係なので、送り仮名だけを対象にするような細かい操作には向きません。
最初は「なぜdwとcwで空白の扱いが違うんだ」と単なるバグだと思っていましたが、ヘルプを読んで意図的な調整だと知ってから納得できました。理屈が分かると、次からは動作を覚え直す必要がなくなるのがVimらしいところだと思います。
この例外を避ける書き方
非対称な仕様を覚えて使い分けるより、そもそも例外の無い書き方に寄せるほうが楽になります。テキストオブジェクトを使えば、iw が単語そのもの、aw が単語と空白、と役割がはっきり分かれます。
ciw " 単語を書き換える(空白は残る)
daw " 単語を空白ごと消す
diw " 単語だけ消す(空白が2つ並ぶ)
こちらはカーソルが単語のどこにあっても結果が同じになるので、位置合わせも要りません。cw の例外を思い出す場面自体が消えます。
dw が行をまたがないという例外もある
非対称な仕様はもう1つあります。行の最後の単語の上で dw を押しても、次の行の先頭までは消えず、その行の末尾で止まります。
w は本来なら次の単語の先頭まで進むモーションなので、そのまま適用すれば改行を巻き込むはずです。ここでもVimは、オペレータと組み合わせたときだけ範囲を切り詰めています。行をまたいで消したいときは、次の行で dd するか J で先につないでください。
繰り返すときに差が出る
この違いが実害になるのは . で繰り返すときです。cw はカーソルが単語のどこにあるかで消える範囲が変わるので、繰り返した先で意図しない結果になります。
ciw なら位置に左右されないので、w で次の単語へ移って .、というリズムがそのまま使えます。同じ書き換えを何か所かで行うことが分かっているなら、最初から ciw で始めておくと後戻りしません。ドットコマンドの記事で繰り返しやすい操作の選び方を扱っています。
まとめ
cwとdwには、モードの違いに加えて、末尾の空白の扱いという非対称な仕様があります。単語頭以外にカーソルがあるときの挙動の違いはcwとciwの違いで扱っています。wやeがどこで単語を区切るかは単語単位の移動のほうで扱っていて、その区切り方がそのままdwの削除範囲になります。
ここで扱ったキーは、ブラウザ上で動くVim道場の書き換えるでそのまま試せます。インストールもログインも要りません。