这有效:
'<,'>s/\v\/\zs(\/)//
'<,'>s/\v(\/)@<=\//BAR/
我只是想知道是否有一种更简单的方法用{}
或vim中的某些内容替换第n个出现的东西。
替换第三个正斜杠“ /”。
/dir1//fas//fooBar/¬
/dir2//\.foobar//fas/¬
/dir//.foo//fas/¬
我将如何替换第四个“ foo”?
foo foo foo foo foo foo foo
foo foo foo foo foo foo foo
答案 0 :(得分:1)
为简单起见,我将讨论如何匹配这些模式,在:s
命令上使用相同的模式,在替代命令中替换它们应以相同的方式工作。
替换第三个正斜杠“ /”。
对于一个字符的匹配,这更容易,因为您可以使用[^/]
查找不属于该匹配的字符。
如果要计算匹配数,则需要从该行的开头开始,因此以^
定位。
到那时,您可以匹配两个“非斜杠”实例,然后匹配一个“斜杠”,然后在第三个实例上,您可以使用\zs
将其标记为实际匹配的开始。
不幸的是,如果我们在比赛中使用/
,则\/
本身需要用/\v^%([^\/]*\/){2}[^\/]*\zs\/
进行转义,但是结果是:
/
包含?
的模式的一个常见技巧是改为使用?\v^%([^/]*/){2}[^/]*\zs/
向后搜索,所以我们可以这样做以提高可读性:
(...)
我在这里使用的模式模式项可能是一些陌生的:
请记住,我们使用的是"verymagic" with \v
,因此上述大多数内容都不需要反斜杠。
我们可以采取一种简洁的捷径来缩短上面的模式(当我们考虑较长单词的情况时,这将对我们有所帮助),也就是说,如果您的模式中的多个位置都有?\v^%([^/]*\zs/){3}
,那么最后一个要匹配的将是定义实际比赛开始的那个。 (请参见:help /\zs
。)
所以我们可以简化为:
\zs
我们先匹配“非斜杠”,再匹配“斜杠”三遍。 [^...]
仅在最后(第三个)匹配项上生效,因此您将最终匹配该行上的第三个斜杠。
现在让我们继续讨论匹配单词的更复杂的情况:
我将如何替换第四个“ foo”?
在这里,我们不能使用\v([^f]|f[^o]|fo[^o])
来匹配“ not foo”。我的意思是,我们可以使用类似/\v^%(%(.%(foo)@<!)*\zsfoo){4}
的名称,但是随着您所匹配的单词的增长,它会迅速增长。还有一种更好的方法。
我们可以使用零宽度的负向后看!有关这个有趣的运算符,请参见:help /\@<!
。简而言之,它采用了前面的原子(我们将在此处使用带有单词的组),并确保该项目与在该位置结束的不匹配。
所以我们可以使用它:
%(foo)@<!
此处的.
确保我们匹配的每个o
不会是foo
中的最后一个foo
。这样,我们就可以准确地计算行中的第一,第二,第三和第四\zs
,并确保我们不会匹配第五,第六或第七。
这又是我们的技巧,将其重复四次(以找到第四场比赛)并握住最后一支*
。
请注意,负向后看对固定单词效果很好,但是如果您开始使用+
或fofo
等复数,则情况会变得更加复杂。查看对操作员的帮助以及警告可能会变慢的警告。运算符还有一个变体,它限制了它返回的字符数,当您匹配一个固定的单词时,您并不一定要使用它,但是对于更通用的匹配而言可能会有所帮助。
与此有关的一个有趣的测试用例是具有重复项的匹配项,例如fofofo
,以及包含重复项的文本,例如fofofofo
或fofofo
。
事实上,通过对这些代码的测试,我发现上面的模式实际上更愿意匹配fofo
中的第二个匹配项,而不是第一个匹配项,如果那是该行中*
的第四次匹配项。这是因为/\v^%(%(.%(foo)@<!){-}\zsfoo){4}
运算符是贪婪的。我们可以改用{-}
来解决此问题,它与可能的最短序列匹配。
修复该错误,我们得到:
You will understand from the links.
这很通用,您可能可以使用任何固定的单词,甚至可以使用带有一些变体的模式(例如大小写,复数形式,替代拼写等)