您如何匹配跳过异常的模式?

时间:2019-01-25 10:31:06

标签: regex vim

vim中,我想在搜索和替换操作中匹配一个正则表达式,但有例外-我要跳过的匹配项列表。

例如,假设我有以下文字:

  

-one- lorem ipsum -two- blah blah-三-现在是时间-四-快棕色-五等,等等。

(但还有很多其他可能性),我想匹配-\(\w\+\)-并用*\1*代替,但跳过(不匹配)-two--four-,所以结果将是:

  

*一个* lorem ipsum-两个-等等*三个*现在是时间-四个-速棕色* 5 *等,等等。

看来我应该可以使用某种断言(向后看,向前看,诸如此类),但是我空白了。

2 个答案:

答案 0 :(得分:3)

您正在寻找负前瞻断言。在Vim中,这是通过:help /\@!完成的,就像Perl中的(?!pattern)

基本上,您说的是此处不匹配FOO,并且通常匹配单词字符

/-\(\%(FOO\)\@!\w\+\)-/

请注意我如何使用非捕获组:help /\%()。最后仍然缺少断言,因此上述内容也将排除-FOOBAR-。由于我们在这里有一个唯一的结束定界符,因此最简单地附加它:

/-\(\%(FOO-\)\@!\w\+\)-/

以您的示例为例,您只需要引入两个分支(对于两个排除项)来代替FOO,就可以了:

/-\(\%(two-\|four-\)\@!\w\+\)-/

或者,通过排除重复的结束定界符:

/-\(\%(\%(two\|four\)-\)\@!\w\+\)-/

这匹配破折号之间的所有单词字符, 除外,如果这些单词形成twofour

答案 1 :(得分:2)

在我的另一个答案中,

负向超前是直接解决方案,但是它的语法有点复杂(而且可能存在一些模式,其中分隔符的规则不是那么简单,然后结果可读性低得多。

在使用替换时,替代是将选择逻辑放入:substitute replacement 部分中。 Vim允许通过:help sub-replace-expression在其中显示Vimscript表达式。

我们在submatch(1)中有捕获的单词(在正常替换中相当于\1),现在只需要检查两个排除的单词即可;如果是其中之一,则通过返回原始的完全匹配(submatch(0))进行无操作替换,否则只需返回捕获的组即可。

:substitute/-\(\w\+\)-/\=submatch(index(['two', 'four'], submatch(1)) == -1 ? 1 : 0)/g

它不比超前模式更短(嗯,我们可以 golf 模式并删除三元运算符,因为布尔值由0 / 1表示),因此在此我仍将使用该模式。但总的来说,很高兴知道有多种方法可以实现:-)