基本的正则表达式

Vim是一个文本编辑器,这意味着大量的Vimscript代码将专注于处理文本。 Vim对正则表达式有着强大的支持,尽管一如既往地也有着一些坑。

把下面的文本打到缓冲区中:

max = 10

print "Starting"

for i in range(max):
    print "Counter:", i

print "Done"

这个就是我们将用来测试Vimscript的正则支持的文本。它恰好是Python代码,但不要担心你看不懂Python。 它只是一个例子。

我会假定你懂得基本的正则表达式。如果你不懂, 你应该暂停阅读本书并开始阅读Zed Shaw的Learn Regex the Hard Way。 (译注:暂无中文版,也可选择别的书,或者just Google it) 在你看完后再继续。

高亮

在开始之前,先花点时间讲讲搜索高亮,这样我们可以让匹配的内容更明显。

:set hlsearch incsearch

hlsearch让Vim高亮文件中所有匹配项,incsearch则令Vim在你正打着搜索内容时就高亮下一个匹配项

搜索

移动你的光标到文件顶部并执行下面命令:

/print

当你逐字母敲打时,Vim开始在第一行高亮它们。当你按下回车来进行搜索时,高亮所有print, 同时移动你的光标到下一处匹配。

现在尝试执行下面的命令:

:execute "normal! gg/print\<cr>"

这将移动到文件顶部并开始搜索print,带我们到第一处匹配。 用的是我们前一章看过的:execute "normal! ..."语法。

要到达文件中的第二处匹配,你仅需在命令的结尾加一点别的。执行这个命令:

:execute "normal! gg/print\<cr>n"

Vim将移动光标到缓冲区中的第二个print(同时高亮所有匹配)。

让我们尝试从反方向开始。执行这个命令:

:execute "normal! G?print\<cr>"

这次我们用G移动到文件结尾并用?来反向搜索。

所有的搜索命令应该已经烂熟于心 —— 我们在让你习惯:execute "normal! ..."惯用法时已经反复练习过, 因为它让你在Vimscript代码中能够做日常在Vim里做的事。

魔力(Magic)

/?命令能接受正则表达式,而不仅仅是普通字符。执行下面命令:

:execute "normal! gg/for .+ in .+:\<cr>"

Vim抱怨说找不到模式!我告诉过你Vim支持正则搜索,所以为何如此?试试下面命令:

:execute "normal! gg/for .\\+ in .\\+:\<cr>"

这次Vim高亮"for"循环,如我们一开始所指望的。在继续阅读之前,花一分钟来想想为何如此。 记住execute接受一个字符串。

答案在此:我们需要这样写命令的原因有二:

  • 首先,execute接受一个字符串,在调用normal!命令时,双反斜杠将转换成单反斜杠。
  • Vim有四种不同的解析正则表达式的"模式"! 默认模式下需要在+前加上一个反斜杠来让它表示"一或多个之前的字符"而不是"一个字面意义上的加号"。

直接在Vim里执行搜索,你很容易就注意到它们的不同,输入下面的命令并按下回车:

/print .\+

现在你可以看到\+的魔力了。双反斜杠仅仅在把模式作为字符串传递给execute时才需要。

字面量字符串

正如我们在字符串那一章提到的,Vim允许你使用单引号来定义可以直接传递字符的字面量字符串。 比如,字符串'a\nb'有四个字符长。

我们可以使用字面量字符串来避免频繁敲打双重反斜杠吗? 先思考这个问题一两分钟,毕竟答案恐怕比你所认为的要更复杂一些。

试试执行下面的命令(注意这次的单引号和单反斜杠):

:execute 'normal! gg/for .\+ in .\+:\<cr>'

Vim带你到文件的顶部却不再移动到第一个匹配的地方。你猜对了吗?

命令之所以不能工作,是因为我们需要模式中的\<cr>被转义成回车,来启动搜索。 因为我们用的是字面量字符串,它并不等价于平常在Vim里键入/for .\+ in .\+:\<cr>, 显然这是无法工作的。

别怕,方法还是比困难多!不要忘了Vim允许字符串连接,所以可以将命令分割成容易理解的一小段。 执行下面的命令:

:execute "normal! gg" . '/for .\+ in .\+:' . "\<cr>"

这种方法可以在传递给execute之前把三小段字符串连接起来, 而且我们可以为正则使用字面量字符串并为其他的使用一般的字符串。

更多的魔力(Very Magic)

你可能会好奇Vimscript的四种不同的正则解析模式和它们跟Python,Perl或Ruby中的正则表达式有何不同。 你可以阅读它们的文档,如果你乐意。不过如果你只想找到一种简单科学的解决办法,请继续读下去。

执行下面的命令:

:execute "normal! gg" . '/\vfor .+ in .+:' . "\<cr>"

我们又一次把正则表达式放在单独的字面量字符串里,而这次我们用\v来引导模式。 这将告诉Vim使用它的"very magic"正则解析模式,而该模式就跟其他语言的非常相似。

如果你以\v开始你的所有正则表达式,你就不用再纠结Vimscript另外三种疯狂的正则模式了。

练习

认真阅读:help magic

阅读:help pattern-overview来看看Vim支持的正则类型。在看到character classes时停下来。

阅读:help match。尝试手动执行几次:match Error /\v.../

在你的~/.vimrc文件中加入使用match来高亮多余的空白为错误的映射。建议使用<leader>w

加入另一个映射来清除匹配项(比如<leader>W)。

加入一个normal模式下的会在进行搜索时自动插入\v的映射。 如果你卡在这个练习上,不要忘了Vim的映射是非常简单的,你只需要告诉它把映射键转换成哪些键。

在你的~/.vimrc文件中加入hlsearchincsearch选项,随你所欲地设置它。

阅读:help nohlsearch。注意这是一个命令并且不是hlsearch的"off mode"。

在你的~/.vimrc文件中加入消除最后一次搜索的匹配项的高亮的映射。