我们通常只要在 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 的正则有四种模式, 分别是 \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 模式或插件, 我平常工作中用到的 CLion 的 IdeaVim 插件非常好使, 能模拟大部分常用的功能, 配合 IntelliJ 平台的代码提示, 开发效率特别高.