假设需要在一个CSS样式文件中查找所有的颜色代码,部分查找目标如下所示。

1
2
3
a { color: #0000EE; }
body { color: #3c3c3c; }
strong { color: #000; }

为此,需要构造一个正则表达式,用于匹配 1个 # 字符以及紧随其后的 3 个或 6 个十六进制字符的目标串 (包括所有数字以及大写或小写的字母 A 到 F)。

1. 使用 magic 搜索模式查找

Vim默认设置下,/#\([0-9a-fA-F]\{6}\|[0-9a-fA-F]\{3}\) 可以查找到所有的目标颜色代码。

在上面的Vim正则表达式搜索命令中,一共用到了 3 类括号:[]、() 和 {},而这 3 类括号都是正则表达式中的特殊字符 (有特殊含义的字符),若要匹配这些特殊字符,必须首先使 \ 进行转义。

正则表达式中,方括号 [] 用于定义待匹配的字符范围,原括号 () 用于标记一个子表达式的开始和结束位置,而花括号 {} 用于指定匹配的长度。

对于Vim的正则表达式引擎来说,方括号 [] 缺省具有特殊含义,不需要转义;圆括号 () 默认会按原义匹配字符,因此需要使用 \ 转义,使其具有特殊含义;花括号 {} 也一样需要使用 \ 转义,但与之对应的闭括号则不用,因为 Vim 会自动推测我们的意图。这就是Vim的 magic 搜索模式。

magic 搜索模式会自动为某些额外的符号赋予特殊含义,例如 .*[ 等。magic 模式的初衷是想能在Vim中更容易地构造简单的正则表达式,但它却没能为诸如 +?(){ 等符号赋予特殊含义,这些符号还必须经过转义才具有特殊含义。

这种”半成品”性质的实现,使得在Vim下构建正则表达式搜索模式,仍然十分麻烦,从上面查找颜色代码的命令就可感受一二。

2. 使用 very magic 搜索模式查找

如上所述,magic 搜索模式下,字符转义的规则制定得比较混乱,容易混淆。

可以使用 \v 开关激活 very magic 搜索模式,统一所有特殊符号的规则:

very magic 搜索模式下,除下划线 _、大小写字母以及数字 0 到 9 之的所有字符都具有特殊含义。

例如,使用 \v 模式开关查找上述匹配十六进制颜色代码的正则表达式可简化为:/\v#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})

由于出现在起始位置的 \v 开关,位于它后面的所有字符都具有特殊含义,用于转义的反斜杠字符就可以去掉,正则表达式的可读性更强了。

3. 使用 very nomagic 搜索模式查找

上面介绍的正则表达式中保留使用的特殊字符,在按模式查找时用起来很方便,但如果想按原义查找对应字符时,又该如何操作呢?

例如,如果想在下面的一段文字中查找 a.k.a,使用Vim命令 /a.k.a. 并不能立马精确地找到目标字符串,因为符号 . 在正则表达式中具有特殊含义,它会匹配任意字符,因此单词 backward 也会被搜索到。

1
2
The N key searches backward...
...the \v pattern switch (a.k.a. very magic search)...

当然,可以使用转义的方法消除 . 字符的特殊含义,即 /a\.k\.a\.

一种更简单的使用方法是使用原义开关 \V 激活Vim的very nomagic 搜索模式。

\V 选项会使得其后的模式中有且只有反斜杠 \ 具有特殊意义,即消除了附加在 .* 以及 ? 等大多数字符上的特殊含义。

使用 \V 原义开关精确搜索 a.k.a 的命令可以简化为:/\Va.k.a.


介绍完上面提到的 Vim magic 搜索模式、very magic 搜索模式和 very nomagic 搜索模式后,是不是反而会觉得规则太多,没法快速地选择所需要的模式。

其实,very magic 和 very nomagic 搜索模式分别是Vim对正则表达式特殊字符的两种极端处理方式。

对于Vim的正则表达式搜索,一个通用的原则是:如果想按正则表达式查找,就用模式开关 \v,如果想按原义查找文本,就用原义开关 \V

4. 界定单词的边界

有些单词,尤其是短词,常常会出现在其他单词内部,比如,the 就会在 these、they、their 等单词中出现。如果想精确匹配 the 这个完整的单词而不是其他词的组成部分,可以使用单词定界符。

在 very magic 搜索模式下,用 <> 符号表示单词定界符

因此,如果将查找命令改为 /\v<the>,就会精确查找到 the 这个单词。

其实,用单词定界符构造精确查找模式的方式早就已经介绍并使用过了。在Vim搜索命令使用方法和技巧一文中已经介绍过,Vim普通模式下使用 *# 可以用于正向或反向精确查找当前光标所在单词。

当然,在 magic、以及 very nomagic 搜索模式下,<> 都必须使用 \ 进行转义才能将其作为单词定界符,而如果想在 very magic 搜索模式下匹配尖括号本身的话,也必须将其转义才有单词定界符的含义。如果你还没理解这两句话,建议再细读下上面关于magic、以及 very nomagic 搜索模式的规则介绍。

5. 界定匹配的边界

在使用Vim的某些场景下,可能想指定一个范围较广的模式,但只对匹配结果的一部分内容感兴趣。

应该明确,当我们谈论一个模式的时候,指的是在查找域输入的正则表达式 (或按原义匹配的文本);而匹配,是指在文档中被高亮显示的文本内容。

一个匹配的边界通常对应一个模式的起始与结尾。但可以使用元字符 \zs\ze匹配进行裁剪,使其成为这个完整模式的一个子集。

元字符 \zs 标志着一个匹配的起始,而元字符 \ze 则用来界定匹配的结束。将二者相结合,可以让我们先定义一个模式来匹配一个较大的文本范围,然后再收窄匹配范围。例如:

如果使用Vim查找命令 /Practical Vim,则文档中所有出现 Practical Vim 的地方都会被搜索出来。一旦将查找模式改为 /Practical \zsVim,则只有单词 Vim 会被高亮选中,而单词 Practical 会被排除于匹配之外,但它仍是模式的一部分。

如此一来,只有紧跟着单词 Practical 的 Vim 才会被查找到,而其他前面不是 Practical 的 Vim 则不会被匹配。这与通过 /Vim 命令进行简单查找的结果有很大不同。

vim-very-magic

嗯,扫一扫就可以找到小女子我啦~