regex - Linux 或 Vim:如何查找和替换匹配的字符串,除了最后一个字符?
问题描述
设想
假设我有一些文本文件:
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
学习新的东西,但如果你不解释更一般的用例,我们就没有什么可以帮助你的了。
一步解决方案是匹配所有情况
savings[A-Za-z]
并将除最后一个字符之外的所有内容替换为savings\.
(实际上这将是savings.
,因为您不需要.
在替换字符串中转义。)
好吧,您可以使用命令捕获最后一个字符并将其放回替换中%s/savings\([A-Za-z]\)/savings.\1/
。但是,为什么不也捕获savings
部分,如%s/\(savings\)\([A-Za-z]\)/\1.\2/
?但在这一点上,我会回过头来智能地使用\zs
and \ze
。
一般来说,有没有办法替换一个匹配的字符串,不包括匹配字符串中的某些字符?在这种情况下,我们希望排除最后一个字符。
“排除某些字符”通常是不可能的,原因很明显:你有一个字符串(它可以有文字部分,例如bla
,对捕获的组的引用,例如\1
, \2
, n...,以及其他东西;但这一切仍然加起来一个字符串)来替换东西。而且这些东西也不可能是字符串。换句话说,如果替换命令以 开头s/ABC/replacement/
,则无法“装饰”ABC
或编写replacement
这样的A
和C
被替换但B
保持不变;如果要保留B
,则必须手动或通过反向引用将其放回原处,例如s/A\(B\)C/x\1y/
.
另一方面,您可以完全通过我从一开始就提到的\zs
and排除搜索字符串的前导和尾随部分。\ze
这两个分别是正向后视和正向前瞻的特殊情况,Vim 通过\@<=
和实现\@=
。例如,%s/savings\zs\ze[^_]/./
等价于可读性较差的%s/\%(savings\)\@<=[^_]\@=/./
,其中[^_]\@=
匹配 non-_
而不“消耗”它们,就像\ze[^_]
在 non- 之前结束匹配一样_
;同样\%(savings\)\@<=
在之后匹配savings
(必须分组,但不需要记住它,所以我使用\%(
and\)
而不是\(
and \)
)。
请注意,还有负面的 lookbehind\@<!
和负面的 lookahead \@!
。这四个统称为lookarounds,允许在正则表达式中加入一些非常复杂的逻辑。
推荐阅读
- python - TypeError:Cursor 类型的对象不是 JSON 可序列化的
- python - 如何将用户输入转换为python中的集合?
- c++ - 如何打印出 GPU 的 OpenGl 版本并将其放入 Opengl 和 C++ 中的字符串中?
- r - bookdown 如何切换到fuse搜索引擎并设置选项
- python - 字节无法转换为所需的输出类型 Bool
- python - 如何在游戏中移动鼠标(Direct X)
- excel - 如何根据工作日使用 VBA 从网站下载文件
- r - 解析 xml 并结合子属性
- r - 我如何从男性平均值中获取女性平均值?
- javascript - 以javascript不可变方式将元素添加到特定索引