我是一个正则表达式的超级电子邮件(只是阅读我关于它们的第一篇文章),同时努力更好地使用vim。我想使用正则表达式来搜索冒号:
的所有实例,这些实例后面没有一个空格,插入一个空格在那些冒号之间他们后面的人物。
如果我从:
开始foo:bar
我想以
结束foo: bar
我到%s/:[a-z]
但现在我不知道%s
语句的下一部分是做什么的。
另外,如何更改:[a-z]
语句以确保它捕获任何不是空格的内容?
答案 0 :(得分:22)
:%s/:\(\S\)/: \1/g
\S
匹配任何不是空格的字符,但您需要记住非空白字符是什么。这就是\(\)
的作用。然后,您可以在替换中使用\1
来引用它。
所以你匹配一个:
,一些非空白字符,然后用:
,空格和捕获的字符替换它。
将此更改为仅在只有一个:
时修改文本非常简单。正如其他人所建议的那样,使用一些零宽度断言将非常有用。
:%s/:\@!<:[^:[:space:]]\@=/: /g
:\@!<
匹配任何非:
,包括该行的开头。这是负前瞻/后瞻断言的一个重要特征。它并不要求实际存在一个角色,只是没有:
。
:
匹配所需的冒号。
[^:[:space:]]
引入了更多正则表达式概念。
外部[]
是一个集合。集合用于匹配内部列出的任何字符。但是,领先^
否定匹配。因此,[abc123]
将匹配a
,b
,c
,1
,2
或3
,但{{1}除了那些字符之外什么都匹配。
[^abc123]
是一个字符类。字符类只能在集合中使用。毫不奇怪,[:space:]
意味着任何空白。在大多数实现中,它直接与C库的[:space:]
函数的结果相关。
将所有内容捆绑在一起,该集合意味着“匹配任何不是isspace
或空白的字符”。
:
是积极的先行断言。它适用于前一个原子(在本例中为集合),意味着该集合是模式成功匹配所必需的,但不会成为替换文本的一部分。
因此,只要模式匹配,我们只需将\@=
替换为自身和空格。
答案 1 :(得分:7)
你想使用一个零宽度的负前瞻断言,这是一种说法寻找一个不是空格但不包含在匹配中的字符的奇特方式:
:%s/: \@!/: /g
\@!
是否定前瞻。
答案 2 :(得分:7)
Vim正则表达式的一个有趣特性是\zs
和\ze
的存在。其他引擎也可能有它们,但它们并不常见。
\zs
的目的是标记匹配的开头,\ze
标记结束。例如:
ab\zsc
匹配c
,仅在您拥有ab
之前。类似地:
a\zebc
只有在a
之后才匹配bc
。你可以混合使用:
a\zsb\zec
仅在b
和a
之间匹配c
。您还可以创建零宽度匹配,这对于您尝试执行的操作非常理想:
:%s/:\zs\ze\S/ /
您的搜索没有大小,只有一个位置。他们用“”代替那个位置。顺便说一下,\S
表示任何字符,但是表示空白字符。
:\zs\ze\S
匹配冒号和非空格之间的位置。
答案 3 :(得分:4)
您可能希望使用:[^ ]
来处理除空格之外的所有内容。正如Matt所说,这将导致你的替换取代额外的角色
有几种方法可以避免这种情况,这里有两种我认为有用的方法
1)使用括号\(\)
包围搜索词的最后一部分,这样您就可以使用/1
在替换词中引用该部分搜索。
您的最终替换字符串应如下所示:
%s/:\([^ ]\)/: \1/g
2)使用\ze
提前结束搜索字词这意味着匹配时必须满足整个搜索字词,但只有\ze
之前的部分才会被突出显示/或替换
您的最终替换字符串应如下所示:
%s/:\ze[^ ]/: /g