Linux 或 Vim:如何查找和替换匹配的字符串,除了最后一个字符?
Linux or Vim: How to find and replace matched string, except for the last character?
场景
假设我有一些文本文件:
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 with savings\.
(Actually this would be savings.
, as you don't need to escape the .
in the replacement string.)
好吧,您可以使用命令 %s/savings\([A-Za-z]\)/savings./
捕获最后一个字符并将其放回替换中。但是为什么不像 %s/\(savings\)\([A-Za-z]\)/./
那样也捕获 savings
部分呢?但在这一点上,我会回去智能地使用 \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
,对捕获组的引用,例如 </code>, <code>
, n..., 和其他东西;但它们仍然加起来是一个字符串)来替换东西。而且这些东西不可能也不是字符串。换句话说,如果替换命令以 s/ABC/replacement/
开头,则无法“修饰”ABC
或将 replacement
写成 A
和 C
被替换但 B
保持不变;如果你想保留 B
,你必须手动或通过反向引用把它放回去,例如s/A\(B\)C/xy/
.
另一方面,您可以排除搜索字符串的前导和尾随部分,完全通过我从一开始就提到的 \zs
和 \ze
。这两个分别是positive lookbehind和positive lookahead的特例,Vim通过\@<=
和\@=
实现。例如,%s/savings\zs\ze[^_]/./
等同于可读性较差的 %s/\%(savings\)\@<=[^_]\@=/./
,其中 [^_]\@=
匹配非 _
而不会“消耗”它们,就像 \ze[^_]
是在非 _
之前结束比赛;类似地 \%(savings\)\@<=
在 savings
之后匹配(必须分组,但不需要记住它,所以我使用 \%(
和 \)
而不是 \(
和 \)
).
请注意,还有负面回顾 \@<!
和负面回顾 \@!
。这4个统称为lookarounds,允许在正则表达式中放入一些非常复杂的逻辑。
您可以使用此模式进行搜索和替换:
:%s/\v^(savings)([[:alnum:]])/./
详情:
%s
: 全局替换
\v
: 很神奇
^
: 开始
(savings)
:匹配测试 savings
并在组 #1 中捕获
([[:alnum:]])
:匹配一个字母数字字符并在组#2 中捕获
.
:替换为捕获值 #1 后跟一个点,然后是捕获值 #2
另一种选择是采用不同的方法,只需替换 table 后缀而不使用 .
前缀
%s/\([^\.]\)table$/.table/
这里的表达式正在搜索没有前面 .
的所有 table
结尾,如果不存在则添加一个
使用负面展望(vim):
:%s/\v(savings)\ze(_proc\.table)@!/&.
\v ........... very magic (avoid backslashes)
() ........... atom
\ze .......... start substitution
(_proc\.table)@! negated patten
& ............. repeat match pattern
@!
否定前一个原子。
场景
假设我有一些文本文件:
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./
捕获最后一个字符并将其放回替换中。但是为什么不像 %s/\(savings\)\([A-Za-z]\)/./
那样也捕获 savings
部分呢?但在这一点上,我会回去智能地使用 \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
,对捕获组的引用,例如 </code>, <code>
, n..., 和其他东西;但它们仍然加起来是一个字符串)来替换东西。而且这些东西不可能也不是字符串。换句话说,如果替换命令以 s/ABC/replacement/
开头,则无法“修饰”ABC
或将 replacement
写成 A
和 C
被替换但 B
保持不变;如果你想保留 B
,你必须手动或通过反向引用把它放回去,例如s/A\(B\)C/xy/
.
另一方面,您可以排除搜索字符串的前导和尾随部分,完全通过我从一开始就提到的 \zs
和 \ze
。这两个分别是positive lookbehind和positive lookahead的特例,Vim通过\@<=
和\@=
实现。例如,%s/savings\zs\ze[^_]/./
等同于可读性较差的 %s/\%(savings\)\@<=[^_]\@=/./
,其中 [^_]\@=
匹配非 _
而不会“消耗”它们,就像 \ze[^_]
是在非 _
之前结束比赛;类似地 \%(savings\)\@<=
在 savings
之后匹配(必须分组,但不需要记住它,所以我使用 \%(
和 \)
而不是 \(
和 \)
).
请注意,还有负面回顾 \@<!
和负面回顾 \@!
。这4个统称为lookarounds,允许在正则表达式中放入一些非常复杂的逻辑。
您可以使用此模式进行搜索和替换:
:%s/\v^(savings)([[:alnum:]])/./
详情:
%s
: 全局替换\v
: 很神奇^
: 开始(savings)
:匹配测试savings
并在组 #1 中捕获
([[:alnum:]])
:匹配一个字母数字字符并在组#2 中捕获
.
:替换为捕获值 #1 后跟一个点,然后是捕获值 #2
另一种选择是采用不同的方法,只需替换 table 后缀而不使用 .
前缀
%s/\([^\.]\)table$/.table/
这里的表达式正在搜索没有前面 .
的所有 table
结尾,如果不存在则添加一个
使用负面展望(vim):
:%s/\v(savings)\ze(_proc\.table)@!/&.
\v ........... very magic (avoid backslashes)
() ........... atom
\ze .......... start substitution
(_proc\.table)@! negated patten
& ............. repeat match pattern
@!
否定前一个原子。