场景
假设我有一些文本文件:
savingstable
savings_proc.table
我想把它改成:
savings.table
savings_proc.table
我的解决方案
我把它分成两个命令:
%s/savings/savings\./g
在此之后,文件显示为:
savings.table
savings._proc.table
所以我按照命令执行:
%s/savings\._/savings_/g
问题
将问题分成两个编辑并不总是有效。有没有办法一步完成所有这些?
一步解决方案是匹配所有 savings[A-Za-z]
的情况,并将除最后一个字符以外的所有字符替换为 savings\.
一般来说,有没有一种方法可以替换自己匹配的字符串,排除匹配字符串中的某些字符?在这种情况下,我们希望排除最后一个字符。
最佳答案
在此特定场景中,%s/savings\zs\ze[^_]/./
会工作,它也让你有机会做 :h \zs
学习新东西,但如果您不解释更一般的用例,那么我们将无能为力。
A one step solution would be to match all cases of
savings[A-Za-z]
and replace everything but the last character withsavings\.
(Actually this would besavings.
, as you don't need to escape the.
in the replacement string.)
好吧,您可以使用命令 %s/savings\([A-Za-z]\)/savings.\1/
捕获最后一个字符并将其放回替换中.但是为什么不也捕获 savings
部分,如 %s/\(savings\)\([A-Za-z]\)/\1.\2/
?但在这一点上,我会回去智能地使用 \zs
和 \ze
.
Generally, is there a way to replace one's matched strings excluding certain characters in the matched string? In this case we would want to exclude the last character.
“排除某些字符”通常是不可能的,原因很明显:你有一个字符串(它可以有文字部分,例如 bla
,对捕获组的引用,例如 \1
, \2
, n...,和其他东西;但它们仍然加起来是一个字符串)来替换东西。而且这些东西不可能也不是字符串。换句话说,如果替换命令以 s/ABC/replacement/
开头,没有办法“装饰” ABC
或写 replacement
这样 A
和 C
被替换但是B
保持不变;如果你想保留 B
,您必须手动或通过反向引用将其放回原处,例如s/A\(B\)C/x\1y/
.
另一方面,您可以完全通过 \zs
排除搜索字符串的前导和尾随部分。和 \ze
我从一开始就提到过。这两个分别是positive lookbehind和positive lookahead的特例,Vim通过\@<=
实现。和 \@=
.例如,%s/savings\zs\ze[^_]/./
相当于可读性较差的 %s/\%(savings\)\@<=[^_]\@=/./
, 其中[^_]\@=
正在匹配非 _
无需“消耗”它们,就像 \ze[^_]
在非 _
之前结束比赛;同样\%(savings\)\@<=
在 savings
之后匹配(必须分组,但没有必要记住它,所以我使用了 \%(
和 \)
而不是 \(
和 \)
)。
请注意,还有负面回顾 \@<!
和负面前瞻\@!
.它们中的所有 4 个统称为环视,并允许在正则表达式中放置一些非常复杂的逻辑。
关于regex - Linux 或 Vim : How to find and replace matched string, 除了最后一个字符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68833928/