Vim 的命令模式記錄

飲馬江南發表於2020-04-05

基本使用

我們通常只要在 Normal 模式下輸入 : 冒號就可以進入命令模式.

行號跳轉

通常我們使用 Vim 的命令中, 最常用且高效的命令就是跳轉行號, 譬如我現在要跳轉到 30 行去改點東西

:30
複製程式碼

我想多跳幾行

可以在一個行數範圍區間內跳轉, 譬如我要在 20 到 30 這個範圍跳轉, 只要這樣

:20, 30
複製程式碼

那假如我只想指定某一行的多少行呢?

:20; +10
複製程式碼

效果同上, 只是可以通過 +/- 來控制

刪除指定行程式碼

Vim 可以在 Normal 模式下使用 dd 來刪除整行程式碼, 我現在可以通過命令模式輸入 30 行然後按 dd 來刪除該行, 能不能再快點呢?

:30 d
複製程式碼

我想刪多點

需求又變了, 如果有多行程式碼需要刪除, 一般我的習慣是進入 視覺化模式選中要刪除的程式碼, 然後按下 d, 其實我們還可以通過命令來刪除多行程式碼, 譬如我要刪除 20, 30 之間的程式碼就可以像這樣

:20, 30 d
複製程式碼

這樣就可以做到刪除指令行範圍內的程式碼, 一個字爽.

從我腳下開始刪

我現在游標在某一行, 但是我不說, 我只想從這一行開始刪到底

:., $ d
複製程式碼

我要刪清爽

現在我們要把當前檔案的所有的程式碼刪掉, 經過上面的例子, 你可能會猜, 這還不簡單

:1, $ d
複製程式碼

是的沒錯, 但是我們還可以這樣

:% d
複製程式碼

移動程式碼

突然我想把 20 到 30 行的程式碼移到 15 行的下面, 一般我們會在刪除的基礎上到指定行下面按 p 貼上, 當然通過命令也能滿足需求.

:20, 30 m 15
複製程式碼

不想移動想複製

繼續剛才的例子, 不過這趟我是想把 20 到 30 行的程式碼複製到 15 行, 只要這樣

:20, 30 t 15
複製程式碼

先到這裡吧, 還有一些 +/- 的操作, 但是我平常基本上沒怎麼用過.

搜尋

最簡單的搜尋

先從普通的搜尋開始, 這個用正則去匹配的, 只需要在命令模式下鍵入斜槓 / 來搜尋就可以了.
然後實戰一下, 假設我們平常寫前端樣式的時候, 有個地方想改一下, 但是隻記得關鍵字

.my-area {
    .my-area__item {
        font-size: 0.24rem;
        /* ... */
    }
    
    .my-area__icon {
        width: 0.5rem;
        height: 0.5rem;
        /* ... */
    }
    /* ... */
}
複製程式碼

只要像下面這樣, 我們就可以全域性將每一行的 my-area 替換成 some-area

:%s /my-area/some-area/
複製程式碼

如果我只是想在當前游標處替換, 我只要把 % 去掉就可以.
繼續舉例子, 假設有如下文字

.test {
    .test__test__item {
        /* ... */
    }
}
複製程式碼

現在我們用上面的 命令來將 test 處理成 hi, 你會發現原本 test__test__item 變成了 hi__test__item, 如果我們是要將所有的 test 改成 hi 怎麼辦?

:%s /test/hi/g
複製程式碼

只要加一個 g 選項就可以解決問題了.

Vim 的正則支援

Vim 的正則有四種模式, 分別是 \v \m \M \V, 一般預設的跟常用的 JavaScript(Perl 風格) 的正則稍微有點區別. 下面只講 \m 模式

元字元 說明
. 匹配任意字元
[xyz] 匹配括號中的任意一個字元, [a-z] 可匹配小寫字母, [0-9] 可匹配數字
[^xyz] 匹配除括號中字元以外的任意字元
\d 匹配數字, 同 [0-9]
\D 匹配數字之外的字元, 同 [^0-9]
\s 匹配空白字元(含<TAB>)
\S 匹配非空白字元
\t 匹配<TAB>
* 匹配 0- 任意個字元
\+ 匹配 1- 任意個字元
\? 匹配 0-1 個字元
\{n,m} 匹配 n-m 個字元
\{n} 匹配 n 個字元
\{n,} 匹配 n- 任意個字元
\{,m} 匹配 0-m 個字元
^ 匹配行首
$ 匹配行尾
\< 匹配單詞首
\> 匹配單詞尾
\ 可以通過 \ 轉義, 如 \\ 表示反斜槓本身
\> 匹配單詞尾
\(\) 分組

\m 模式下跟常規正則的不同

Vim Perl 說明
\+ + 匹配 1- 多個字元
\? ? 匹配 0-1 個字元
\{n,m} {n,m} 匹配 1-m 個字元
\(\) () 分組

正則變數

大概瞭解了一下 Vim 支援的正則之後, 我們可以玩點花頭, 先來匹配一下 aabbbaa, 找規律就好了, 第一部分是兩個 a, 就假設有多個 a\+, 第二部分不是 a 同時假設有多個, 所以是 [^a]\+, 第三部分跟第一部分一樣, 其實可以用正則的變數 \1 來表示第一部分匹配的規則, 但是第一部分沒有加 \(\), 這樣是沒法用變數的, 所以最後就是這樣

:/\(a\+\)[^a]\+\1
複製程式碼

接著把 aa 換成 bbb, bbb 換成 aa

:s /\(a\+\)\([^a]\+\)\1/\2\1\2/
複製程式碼

其實還有一種函式用法

:s /\(a\+\)\([^a]\+\)\1/\=submatch(2) . submatch(1) . submatch(2)
複製程式碼

Vim 玩法還是蠻多的, 就很棒

跟命令模式指令結合

其實這個只要舉一反三就行, 不過還是備個忘, 譬如現在有一段程式碼, 我要把空行刪掉

#include <stdio.h>
        
int main(int argc, char **argv) {
    printf("hello world");
    return 0;
}
複製程式碼

而空行可能有 <TAB> 或 空格

:/^\s*$/d
複製程式碼

通過 d 指令這樣就可以把 int main 上面那行空行刪掉了.

再來個貪婪模式跟惰性模式, 現在有一串數字 123 1234 12345 123456, 這樣替換就會換成 a a a a

:s /\d\{2, 6}/a/g
複製程式碼

而下面這樣替換就會變成 a3 aa aa5 aaa

:s /\d\{-2, 6}/a/g
複製程式碼

要想使用貪婪模式, 就不要用 \{-, 這樣就是匹配優先的行為, 把 - 去掉就是忽略優先的行為, 也就是惰性模式.

其他

Vim 的正則還支援環視等操作, 但是我不會, 就這樣吧.


身為 95 後, 我為什麼要用 Vim. 從上面的例子中可以看出 Vim 編輯文字方面是高效的, 君不見基本上每個編輯器都提供了 Vim 模式或外掛, 我平常工作中用到的 CLionIdeaVim 外掛非常好使, 能模擬大部分常用的功能, 配合 IntelliJ 平臺的程式碼提示, 開發效率特別高.