- Published on
Vim 語法系統:動詞 + 量詞 + 名詞

Vim 系列文章
- Vim 生存指南:模式與移動
- Vim 編輯基礎:輸入、刪除和複製貼上
- Vim 選取模式:三種 Visual Mode
- Vim 語法系統:動詞 + 量詞 + 名詞 (本篇)
- Vim 搜尋技巧:快速定位與取代
- Vim 效率倍增:重複與自動化
- Vim 客製化:設定與 IDE 整合
前幾篇我們學了移動、編輯和選取,但都是單一指令。這篇要介紹 Vim 最強大的概念:動詞 + 量詞 + 名詞 的組合邏輯,以及文字物件。搞懂這些,你就能用幾個簡單的規則組合出各種操作
Vim 的語法系統
Vim 的指令就像英文一樣,有動詞、量詞和名詞
[量詞] + 動詞 (Operator) + [量詞] + 名詞 (Motion) = 動作
量詞是選填的,可以放在動詞前面或名詞前面,效果一樣
基本組合(沒有量詞)
d(刪除) +w(word) =dw= 刪除一個 wordc(修改) +$(到行尾) =c$= 修改到行尾y(複製) +j(下一行) =yj= 複製這行和下一行
加上量詞
d+2w=d2w= 刪除 2 個 word3+dw=3dw= 刪除 3 個 word(效果同d3w)y+5j=y5j= 複製往下 5 行
這就是為什麼 Vim 用起來很爽:你不用死背上百個指令,只要記住幾個動詞、名詞,再加上量詞,就能組合出各種操作
常用動詞 (Operators)
| 動詞 | 作用 | 記憶 |
|---|---|---|
d | 刪除 | delete |
c | 修改(刪除並進入 Insert Mode) | change |
y | 複製 | yank(Vim 用語) |
> | 增加縮排 | |
< | 減少縮排 | |
= | 自動縮排 | |
gu | 轉小寫 | |
gU | 轉大寫 |
常用名詞 (Motions)
| 名詞 | 範圍 |
|---|---|
w | 到下一個 word 開頭 |
e | 到當前 word 結尾 |
b | 到上一個 word 開頭 |
$ | 到行尾 |
0 | 到行首 |
gg | 到檔案開頭 |
G | 到檔案結尾 |
j / k | 下一行 / 上一行 |
文字物件 (Text Objects)
除了 Motion,Vim 還有一種特別的名詞叫「文字物件」。它可以選取一個完整的結構,像是一個 word、一對引號內的內容、一對括號內的內容等
i 和 a 的差別
i= inner(內部),不包含邊界a= around(周圍),包含邊界
say "hello world" here
^ ← 游標在引號內
di" → 刪除 hello world(引號內的內容)
da" → 刪除 "hello world"(包含引號)
常用文字物件
| 文字物件 | 範圍 |
|---|---|
iw / aw | 一個 word |
i" / a" | 雙引號內 |
i' / a' | 單引號內 |
i) / a) | 小括號內(ib / ab 也可以) |
i] / a] | 中括號內 |
i} / a} | 大括號內(iB / aB 也可以) |
it / at | HTML/XML 標籤內 |
ip / ap | 段落 |
文字物件的搜尋規則
游標不一定要在括號或引號內部才能使用文字物件
規則 1:往右搜尋
如果游標不在目標結構內,Vim 會在同一行往右找最近的
let x = foo("hello")
^ ← 游標在 x 上
ci" → 會修改 "hello"(往右找到最近的引號)
規則 2:往外擴展
如果在嵌套結構內,會先選取最內層的,再操作會往外擴展
if (a && (b || c))
^ ← 游標在 b 上
di) → 刪除 b || c(最內層的括號)
文字物件範例
ciw → 修改整個 word
ci" → 修改引號內的內容
ci( → 修改括號內的內容
da{ → 刪除大括號(包含括號本身)
yip → 複製整個段落
dw vs diw vs daw
這三個看起來很像,但結果不同
hello world foo
^ ← 游標在 w 上
dw(Motion)
刪除從游標位置到下一個 word 開頭
hello world foo
^
dw →
hello foo ← 刪除 "world "(從 w 到下一個 word)
^
diw(Text Object - inner word)
刪除整個 word,不包含空格
hello world foo
^
diw →
hello foo ← 刪除 "world",保留兩邊空格
^
daw(Text Object - around word)
刪除整個 word,包含周圍的空格
hello world foo
^
daw →
hello foo ← 刪除 "world" 加上一邊的空格
^
什麼時候用哪個?
dw:游標在 word 開頭,想刪到下一個 worddiw:想刪掉整個 word,但保留空格(例如要換成別的字)daw:想刪掉整個 word 和空格(例如刪掉一個參數)
搭配 Visual Mode
文字物件和 Visual Mode 搭配很好用
function hello() {
console.log("hello");
console.log("world");
}
游標在函數內任意位置
vi{ → 選取大括號內的所有內容
va{ → 選取大括號(包含括號本身)
在 Visual Mode 中也可以用文字物件擴展選取
say "hello world" here
^ ← 游標在引號內
按 v 進入 Visual Mode,然後
按 iw → 選取 "world"
按 i" → 選取 "hello world"(引號內全部)
按 a" → 選取 "hello world" 包含引號
組合範例
dw → 刪除到下一個 word 開頭
de → 刪除到當前 word 結尾
d$ → 刪除到行尾
d0 → 刪除到行首
dG → 刪除到檔案結尾
cw → 修改到 word 結尾,進入 Insert
c$ → 修改到行尾,進入 Insert
yw → 複製一個 word
y$ → 複製到行尾
量詞讓組合更強大
d2w → 刪除 2 個 word
c3w → 修改 3 個 word
y5j → 複製往下 5 行
gUw → 把一個 word 轉大寫
3dd vs d3j:看起來像,但不一樣
這是一個容易搞混的地方
3dd = 重複 dd 三次 = 刪除 3 行
1 aaa
2 bbb ← 游標在這
3 ccc
4 ddd
5 eee
按 3dd
1 aaa
2 eee ← 刪除了 bbb、ccc、ddd(3 行)
d3j = 刪除到「往下 3 行」的範圍 = 刪除 4 行
1 aaa
2 bbb ← 游標在這
3 ccc
4 ddd
5 eee
6 fff
按 d3j
1 aaa
2 fff ← 刪除了 bbb、ccc、ddd、eee(4 行)
差別在於:
3dd:量詞修飾的是dd(整行操作),所以是「做 3 次刪除整行」d3j:3j是「往下移動 3 行」,所以d3j是「刪除從這裡到往下 3 行的範圍」(包含當前行 + 下面 3 行 = 4 行)
動畫展示:組合技
delete some words here
^
按 dw
some words here
^
按 d2w
here
^
change this word
^
按 cw
change word ← "this" 被刪除,進入 Insert Mode
^
輸入 "that"
change that word
本篇重點整理
語法公式
[量詞] + 動詞 + [量詞] + 名詞 = 動作
量詞放動詞前或名詞前都可以
d2w = 2dw = 刪除 2 個 word
常用動詞
d → 刪除
c → 修改(刪除 + 進入 Insert)
y → 複製
> / < → 增加/減少縮排
gu / gU → 轉小寫/大寫
常用名詞
w/e/b → word 相關
$/0 → 行尾/行首
gg/G → 檔案開頭/結尾
j/k → 下一行/上一行
文字物件
i = inner(內部),a = around(周圍)
iw/aw → 一個 word
i"/a" → 引號內
i)/a) → 括號內
i}/a} → 大括號內
常用組合
dw/cw/yw → 操作一個 word
d$/c$/y$ → 操作到行尾
ciw/diw → 修改/刪除整個 word
ci"/di" → 修改/刪除引號內容
vi{/va{ → 選取大括號內容