文章目录
- 一、vim 替换表达式的语法格式
- 二、vim 关于 range 的表达式
- 三、vim 关于 flags 的元字符
- 四、vim 关于数量的元字符
- 五、环视和固化分组
- 六、vim 替换表达式的示例
- (一)结合 copy 命令使用
- (二)结合 move 命令使用
- (三)结合 normal 命令使用
- (四)匹配重复性模式
- (五)指定重复次数
- (六)匹配可选项
- (七)多选一匹配模式/多选结构
- (八)引用分组
- (九)替换内容的特殊字符
- 1. & 符号
- 2. ~ 符号
- 3. \u 和 \l
- 4. \U 和 \L
- (十)界定 pattern 的子集
一、vim 替换表达式的语法格式
语法格式:[range]substitute/from/to/[flags]
或者 [range]s/src/dest/[para]
或者 [range]s/pattern/replacement/[options]
说明:substitute
命令可以对一个指定范围的区域执行替换操作,可以简写为 s
。该命令是将[range]所指定范围中的字符串"from"替换为"to",“from” 可以使用正则表达式。
二、vim 关于 range 的表达式
range
意为检索范围,如果不指定 range
,则表示当前行。vim 表示范围或者位置的表达式或者元字符如下表所示:
表达式及元字符 | 说明 |
---|---|
% | 整个文档,即每一行,所有行,等价于 1,$ |
1 | 表示整个文档的第一行 |
$ | 表示行尾,这是虚拟的概念;另外还表示整个文档的最后一行 |
^ | 表示行首,这是虚拟的概念 |
0 | 虚行,表示第一行的上方 |
. | 当前行 |
'm | 包含位置标记m的行,不知道干嘛的 |
\< | 匹配单词词首,在 very magic 下,不需要转义,< 就可以匹配词首,详解《关于 vim 的 magic 设置》 |
\> | 匹配单词词尾 |
\zs | 界定 pattern 的子集的开始,不好理解是吧,下面的例子吧~ |
\ze | 界定 pattern 的子集的结束 |
'<,'> | 可视模式下的范围,在选择好文本内容后,按冒号 : 后自动出现 '<,'> 范围,不用自己输入 |
m,n | 从m行到n行。例如,2,3 表示第二行至第三行 |
.+3,$-5 | 作用范围从当前行其下的第3行,到倒数第6行 |
三、vim 关于 flags 的元字符
有的表达式范例写成 para,意思相同。
命令执行标记 | 说明 |
---|---|
g | 表示替换一行中的所有匹配到的源字符串,表示替换行中的所有匹配点 |
c | 每次替换前询问,告诉 substitute 命令要执行每个替换前请求用户确定 |
e | 出错不提示 |
i | 忽略大小写 |
p | 列印 |
四、vim 关于数量的元字符
表示数量的元字符,也叫“限定符”,也叫“量词”。
vim | perl | 意义 |
---|---|---|
* | * | 表示任意数量(匹配优先) |
\+ | + | 表示 1 个或多个(匹配优先) |
\? 或 \= | ? | 表示 0 个或 1 个(匹配优先),\? 不能在 ? 命令(逆向查找)中使用 |
\{n,m} | {n,m} | 表示 n 个到 m 个(匹配优先) |
\{n,} | {n,} | 表示 n 个到无限个,即最少 n 个(匹配优先) |
\{,m} | {,m} | 表示 0 个到 m 个,即最多 m 个(匹配优先) |
\{n} | {n} | 表示 n 个 |
\{-n,m} | {n,m}? | 表示 n 个到 m 个(忽略优先) |
\{-} | *? | 表示任意数量(忽略优先), |
\{-1,} | +? | 表示 1 个或多个(忽略优先) |
\{-,1} | ?? | 表示 0 个或 1 个(忽略优先) |
注:匹配优先,是指整个正则表达式可以匹配成功的前提下,尽可能匹配更多的字符;忽略优先,是指在整个正则表达式可以匹配成功的前提下,匹配的字符数越少越好。具体可以详见《正则表达式的贪婪模式、非贪婪模式、占有模式
》。
五、环视和固化分组
vim 还支持环视和固化分组的功能。
vim | perl | 意义 |
---|---|---|
\@= | (?= | 顺序环视 |
\@! | (?! | 顺序否定环视 |
\@<= | (?<= | 逆序环视 |
\@<! | (?<! | 逆序否定环视 |
\@> | (?> | 固化分组 |
\%(atom\) | (?: | 非捕获型括号 |
和 perl 稍有不同的是,vim 中的环视和固化分组的模式的位置与 perl 不同。 例如,查找紧跟在 foo 之后的 bar,perl 将模式写在环视的括号内, 而 vim 将模式写在环视的元字符之前。
perl 的写法: /(?<=foo)bar/
vim 的写法: /\(foo\)\@<=bar
六、vim 替换表达式的示例
表达式示例 | 解释 |
---|---|
s/old/new | 将当前行的第一个字符串old 替换为new |
s/old/new/g | 将当前行的所有字符串old 替换为new |
90s/old/new/g | 将第90行的所有字符串old 替换为new |
90,93s/old/new/g | 在第 90与 93 行之间寻找old 这个字符串,并将该字符串替换为 new |
%s/old/new/g | 将文本中所有的字符串old 替换为new |
%s/old/new/gc | 在整个文档中寻找old 字符串,并将该字符串替换为new ,且在替换前会显示提示字符给用户确认 (confirm) 是否需要取代 |
%s/^struct/int/g | 将所有以struct 开头的字符串替换为int,^ 表示行首 |
%s/^/new/g | 在每一行的行首插入new |
1,$s/old/new/g | 1 表示第一行,$ 表示最后一行,g 表示替换行中的所有匹配点,表达式解释:全文查找字符串 old ,查找到后替换成字符串 new 。 |
%s/\s\+$// | 删除行尾一个或多个空格和 tab。% 表示在所有行搜索,第一个 s 表示替换,$ 表示行尾,+ 表示一个或多个,需要使用 \ 转义,就是 \+ ,第二个 s 表示空格,也要转义,就是 \s ,替换命令的 “to” 部分是空的:// ,正斜杠之间是空的,这样就会删除那些匹配的空白字符。整个表达式的解释:在每行中查找匹配一个或者多个空格,匹配到后替换成空,也就是删除了。 |
%s/\s\+$ | 同上,只是把 “to” 部分省略掉 |
%s/\s\+ | 删除行首多余的空格和 tab,没有使用 g ,默认替换行中首次出现的源字符串,这里就是空格,所以若行首有空格,会首次匹配到,然后被替换成“空”。 |
%s/^\s*// | 删除行首多余空格。% 表示在所有行搜索,第一个 s 表示替换,^ 表示行首,\s 表示空格,* 表示任意数量,// 说明替换的内容为空。整个表达式的解释:在每行的行首匹配任意数量的空格,匹配到后替换成空,也就是删除每行行首的空格。 |
%s/^ *// | 含义同上,这个表达式啥意思? |
%s/^$// | 删除沒有內容的空行。% 表示在所有行搜索,第一个 s 表示替换,^ 表示行首,$ 表示行尾,^$ 表示行首和行尾之间啥都没有,即空行,// 说明替换的内容为空。表达式解释:在整个文档中检索空行,查找到就替换为空。 |
g/^$/d | 含义同上,这个表达式啥意思? |
%s/^\s*$// 或者 | 删除包含任意个空格的空行。% 表示在所有行搜索,第一个 s 表示替换,^ 表示行首,$ 表示行尾,\s 表示空格,* 表示任意数量,^\s*$ 表示包含任意数量的空格的行。表达式解释:在整个文档中检索匹配包含任意个空格的行,查找到就替换为空。 |
g/^\s*$/d | 含义同上 |
%s/^[ |\t]*$// | % 表示在所有行搜索,第一个 s 表示替换,^ 表示行首,$ 表示行尾,\t 表示 TAB,中括号表达式 [ |\t] 表示空格或者 TAB,其实也可以写成 [\s|\t] 。表达式解释:删除包含任意个空格或者 TAB 的空行。 |
g/^[ |\t]*$/d | 含义同上 |
%s/linux/FreeBSD/ | 在整个文本的每一行检索字符串 linux,将每行匹配到的第一个 linux 替换为 FreeBSD 。注意:后面没有加上 g 标记,针对的是每行第一次匹配到的源字符串。 |
s/linux/FreeBSD/ | 不加 % ,则只作用于当前行,即只在光标所在行查找。没有具体指定范围,默认情况下只会替换当前行中第一次匹配到的源字符串,若要替换一行中所有匹配到的字符串,必须在命令后加 g 标记来修饰。 |
%s/linux/FreeBSD/g | 将整个文档中的字符串 linux 替换成 FreeBSD。% 表示在所有行查找匹配,g 表示更换一行中所有匹配到的源字符串,s 是替换的指令 |
%s/linux/FreeBSD/gc | 将整个文档中的字符串 linux 替换成 FreeBSD,且替换前询问用户。 |
%s/\<four/4/g | 用 \< 来指定匹配单词开头。\<four 表示以 four 为单词首。例如,fourfive 会被替换成 4five,而 fivefour 则不会改变,但是 fourty 则会变成 4ty ,显然不是我们要的结果,怎么办?使用这个 %s/\<four\>/4/g ,\> 表示单词尾,\<four\> 表示单词首和单词尾之间只有 four ,即只查找 four 这个单词,匹配到替换成 4 。 |
%s/abc\(.*\)xyz/xyz\1abc/g | 直接输入 ( 会被 vim 认为属于字符串的内容,其实不是,( 就是一个小括号,所以需要转义,故书写为 \( ,) 同理要转义。. 表示任意单个字符,就是* 表示任意数量,.* 表示任意数量的 . ,而 . 代表任意一个字符,所以 .* 表示任意数量的任意字符(MySQL 中的通配符 * 就可以表达这个含义)。例如,a 可以匹配 . ,ab 就不能匹配 . 了,但是 .* 就可以匹配了,你可以理解为需要 2 个. 来匹配 ab ,一个 . 匹配 a ,另外一个. 匹配 b 。所以最后 (.*) 表示任意数量的字符,而且这样括号起来,可以被后面的表达式引用。例如,xyz\1abc ,其中 \1 就是引用前面源字符串正则表达式中的第 1 个括号中的内容,那么就相当于 xyz\(.*\)abc 。表达式解释:把文本中的所有字符串 abc……xyz 替换为 xyz……abc 。 |
%s/\(abc\)\(.*\)\(xyz\)/\3\2\1/g | 含义同上,只是后面的替换字符串表达式倒序引用了前面的 3 个括号的内容,实际表达式就是 %s/\(abc\)\(.*\)\(xyz\)/\(xyz\)\(.*\)\(abc\)/g |
%s/\(a.c\)\{3\}$/lwx/g | $ 表示行尾,这是个虚拟的概念。{3} 表示前面的字符串要出现 3 次,(a.c) ,小括号包裹的内容作为一个整体,所以小括号的内容整体要出现3次,. 表示任意一个字符,那么像这样的 abcabcabc,adcafcagc 等都可以匹配,只要确保以 a 开头,以 c 结尾,中间任意一个字符所组成的整体出现 3 次就可以了。表达式解释:在文本的每行行尾查找匹配表达式 (a.c){3} 的字符串,查找到则替换成字符串 lwx 。注意:在 vim 的正则表达式中要使用常规正则表达式的元字符(如小括号 ( ,大括号 { ),以正常使用常规正则表达式,必须在元字符前加反斜杠,否则 vim 会把很多元字符当成普通字符 |
(一)结合 copy 命令使用
[range] copy [address]
,将 range
的内容复制到 address
下方,copy
等价于 co
,等价于 t
。
表达式示例 | 解释 |
---|---|
6 t . | 把第6行复制到当前行下面 |
6 t | 同上,只是省略了 . |
. t $ | 把当前行复制到文本末尾,注意这里的 $ 就不是行尾的含义了,而是整个文档的最后一行的下方位置,其实也是虚拟的概念 |
t $ | 同上 |
(二)结合 move 命令使用
[range] move [address]
,将 range
的内容移动到 address
下方,move
等价于 m
表达式示例 | 解释 |
---|---|
. m $ | 将当前行移动到文本末尾 |
(三)结合 normal 命令使用
normal
表示“普通命令模式”。
[range] normal [command]
,对 range
范围的文本内容执行“普通命令模式”下的命令 command
表达式示例 | 解释 |
---|---|
% normal I // | 表示在整个文档的行首插入 // ,% 表示整个文档,normal I ,表示执行普通命令模式的指令 I ,这个指令 I 就是在行首插入文本的意思,通常用于注释代码 |
2,4 normal A ++ | 在第2到第4行的末尾添加 ++ ,A 就是在行尾插入文本的意思 |
(四)匹配重复性模式
表达式示例 | 解释 |
---|---|
/a* | 星号 * 规定在它前面的项可以出现任意次。因此 /a* 会匹配 a ,aa ,aaa 等等,并且也匹配空字符串,因为零次也包含在内。 |
/ab* | 星号 * 仅仅应用于那个紧邻在它前面的项。因此 /ab* 表示 b 可以重复任意次,所以会匹配 a ,ab ,abb ,abbb 等等。 |
/ab\+ | 要避免匹配空字串,使用 \+ 。这表示前面一项可以被匹配一次或多次,因此 /ab\+ 会匹配 ab ,abb ,abbb 等等。它不匹配后面没有跟随 b 的 a 。 |
(五)指定重复次数
要匹配某一项的特定次数重复,使用 \{n,m}
这样的形式。其中 n
和 m
都是数字。在它前面的那个项将被重复 n
到 m
次,包含 n
和 m
。
表达式示例 | 解释 |
---|---|
/ab\{3,5} | 表示紧邻的 b 可以重复出现 3 次,4 次,5 次,所以可以匹配 abbb ,abbbb 以及 abbbbb 。 |
当 n
省略时,被默认为零。当 m
省略时,被默认为无限大。当 ,m
省略时,就表示重复正好 n
次,关于区间量词的表达式如下表所示:
模式 | 匹配次数 |
---|---|
\{,4} | 0,1,2,3 ,4 |
\{3,} | 3,4,5,无限大,大于等于 3 |
\{0,1} | 0 或 1,等同 \= |
\{0,} | 0 或更多,等同 * ,大于等于 0 |
\{1,} | 1 或更多,等同 \+ ,大于等于 1 |
\{3} | 3 |
(六)匹配可选项
表达式示例 | 解释 |
---|---|
/folders\= | 要匹配一个可选项,用 \= 。 /folders\= 表示紧邻的 s 可有可无,也就是 0 个或者 1 个,所以匹配 folder 和 folders 。 |
(七)多选一匹配模式/多选结构
\|
就是或的意思,表示两者中的一个。
表达式示例 | 解释 |
---|---|
/foo\|bar | 在一个查找模式中,“或”运算符是 \| 。/foo\|bar 这个命令匹配 foo 或 bar 。 |
(八)引用分组
pattern 中圆括号 ()
包含的部分就是分组,后面可以使用 \n
进行引用,正常情况下,n 的取值范围是 [1-9]
。
源字符串:liaowenrettliaowenrtrdfgf
:s/\(liao\)\(wen\)/\2\1/g
执行以上命令后,源字符串中的“liaowen”全部替换成“wenliao”。\1
引用 pattern 的第 1 个分组 (liao)
匹配到的字符串;\2
引用第 2 个分组 (wen)
匹配到的字符串。
(九)替换内容的特殊字符
1. & 符号
&
替换为模式的匹配,也即如果 pattern 匹配 helloworld
,那么 &
就引用 helloworld
。
示例 1:
:s/man/&,&,what/gc
man
被替换成 man,man,what
示例 2:
:s/.*/{&}/g
没有指定 range,则仅在当前行匹配查找,所以上面的命令就是将当前行加了一个大括号 {}
。
2. ~ 符号
~
替换为上一次替换命令所用的 replacement
。
示例 1:
:s/their/our/g # their --> our
:s/his/~/g # his --> our
:s/my/~/g # my --> our
3. \u 和 \l
\u
:把后一个字母转成大写。
\l
:把后一个字母转成小写。
示例 1:
:s/\(what\)/\u\1/g
\1
引起 pattern 的第 1 个分组所匹配到的字符串,上述命令就是 what
,那么 \uwhat
就是 What
,所以就是把 what
替换为 What
。
示例 2:
:s/.*/\u&/g
.*
表示匹配任意数量的任意字符(除了换行符);&
引用 pattern 匹配到的内容。所以上述的命令表示将当前行的第 1 个字符大写,大哥,你还要确保当前行的第 1 个字符是英文字母才行。
:%s/.*/\u&/g
以上的命令表示将整个文档的每行的第 1 个字符转成大写。
示例 3:
:s/[a−zA−Z]\+/\u&/g
将当前行匹配到的英文字符串的首个字母转成大写。
4. \U 和 \L
\U 表示后面的字符全部转成大写;\L 表示后面的字符全部转成小写。
示例 1:
:s/restore/\U&/g # restore --> RESTORE
示例 2:
:s/ResTore/\L&/g # ResTore --> restore
示例 3:
\U
和 \e
或 \E
组合使用,表示 \U
和 \E
之间的字符转成大写;\L
和 \e
或 \E
组合使用,表示 \L 和 \E
之间的字符转成小写。
:s/restore/re\Usto\ere/ # restore --> reSTOre
(十)界定 pattern 的子集
元字符 \zs
标志着一个匹配的起始,而元字符 \ze
则用来界定匹配的结束。将二者相结合,可以让我们先定义一个模式来匹配一个较大的文本范围,然后再收窄匹配范围。
我想要查找 Practical 后面的 Vim。
/Practical Vim
使用上述的 pattern 文档中所有出现 Practical Vim 的地方都会被搜索出来。一旦将查找模式改为:
/Practical \zsVim
则只有单词 Vim 会被高亮选中,而单词 Practical 会被排除于匹配之外,但它仍是模式的一部分。
如此一来,只有前面紧跟着单词 Practical 的 Vim 才会被真正匹配到,而其他前面不是 Practical 的 Vim 则不会被匹配。这与通过 /Vim
命令进行简单查找的结果有很大不同。其实也可以使用“逆序肯定环视”来匹配。