在vim
中,我想在搜索和替换操作中匹配一个正则表达式,但有例外-我要跳过的匹配项列表。
例如,假设我有以下文字:
-one- lorem ipsum -two- blah blah-三-现在是时间-四-快棕色-五等,等等。
(但还有很多其他可能性),我想匹配-\(\w\+\)-
并用*\1*
代替,但跳过(不匹配)-two-
和-four-
,所以结果将是:
*一个* lorem ipsum-两个-等等*三个*现在是时间-四个-速棕色* 5 *等,等等。
看来我应该可以使用某种断言(向后看,向前看,诸如此类),但是我空白了。
答案 0 :(得分:3)
您正在寻找负前瞻断言。在Vim中,这是通过:help /\@!
完成的,就像Perl中的(?!pattern)
。
基本上,您说的是此处不匹配FOO
,并且通常匹配单词字符:
/-\(\%(FOO\)\@!\w\+\)-/
请注意我如何使用非捕获组(:help /\%(
)。最后仍然缺少断言,因此上述内容也将排除-FOOBAR-
。由于我们在这里有一个唯一的结束定界符,因此最简单地附加它:
/-\(\%(FOO-\)\@!\w\+\)-/
以您的示例为例,您只需要引入两个分支(对于两个排除项)来代替FOO
,就可以了:
/-\(\%(two-\|four-\)\@!\w\+\)-/
或者,通过排除重复的结束定界符:
/-\(\%(\%(two\|four\)-\)\@!\w\+\)-/
这匹配破折号之间的所有单词字符, 除外,如果这些单词形成two
或four
。
答案 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
表示),因此在此我仍将使用该模式。但总的来说,很高兴知道有多种方法可以实现:-)