Vim语法突出显示(正则表达式)

时间:2012-08-03 01:38:57

标签: regex vim vim-syntax-highlighting

我试图使用c.vim插件在Vim中突出显示一个成员变量。

例如,在

struct sockaddr_in sa;
sa.sin_family = AF_INET;

我想强调sin_family

所以,这是我的语法匹配代码:

syn match   cCustomMember "\(\.\)\@<=[a-zA-Z0-9_]\+\s*\((\)\@!"
hi def link cCustomMember Number

基本上我在这里要说的是前面必须有一个.,后跟多个单词字符,可选地后面跟空格,并确保没有括号跟随。

但是突出显示正则表达式的上述语法似乎在Vim中无法正常工作。 例如,如果我有这样的代码:

getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), CONNECT_FAIL.msg());

.msg和.code突出显示,但最后一个字母不是。但我不想突出显示成员函数(以圆括号结尾)

我认为它有点类似于python中的这个正则表达式问题:

a = re.compile("(?<=\.)(?:\w+)(?!\()")
print a.search(".test(").group() #produces tes, which it's desired to match nothing
print a.search(".test").group()  # produces test

如何对整个群体进行否定预测,而不是单个字母。

1 个答案:

答案 0 :(得分:3)

解释

您正在努力解决的问题是由于现代正则表达式引擎在查找匹配项时的基本方式,称为backtracking。 Jan Goyvaerts在他的帖子“Unintended Backtracking Can Bite You”中简明扼要地说:

  

当正则表达式引擎遇到与字符串中的下一个字符不匹配的正则表达式标记时,会发生回溯。然后,正则表达式引擎将备份到目前为止匹配的部分内容,以尝试不同的替代方案和/或重复。理解这个过程将会在猜测和理解正则表达式为什么与它做什么和不做什么相匹配之间产生差异。

在您的情况下,当前瞻断言匹配时,正则表达式引擎将回溯,测试匹配的较短组合 - .cod.ms都可以。下面显示了发生了什么,垂直条分隔正则表达式已经从字符串.code()的其余部分消耗的字符:

.|code()   # good start => try next char
.c|ode()   # matches => try next char
.co|de()   # matches => try next char
.cod|e()   # matches => try next char
.code|()   # whoops, next char is "(" => track back
.cod|e()   # matches => we’re done here

请注意,只有在使用贪婪量词时才会这样,就像在代码中一样;延迟量词将与.c匹配。请参阅the Regex Tutorial on lazy versus greedy quantifiers

解决方案

解决这个问题的显而易见的方法是禁止在前瞻之前进行回溯,有效地“锁定”正则表达式已经消耗的模式部分:成员函数永远不会匹配。一些正则表达式引擎将允许您使用 atomic grouping 或甚至possessive quantifier(基本上是用于原子分组的语法糖)来完成此操作 - 更为人所知的是那些列出的之前链接的页面。然而,Vim的正则表达式引擎is not one of them

一种不那么简单而且更脆弱的方法是重新定义您正在寻找的东西:而不是匹配开头的否定前瞻断言,使用正面前瞻断言匹配将成员变量与其他代码分隔的所有有效字符(空白,逗号,分号,结尾符号,行尾 - 检查您的来源以获取更多信息) - 基本上只有开头和其他名称字符。我会留给你翻译成Vim’s regex syntax