如何使 vim 替换重复直到没有更多匹配项?
How do I make vim substitute repeat until there are no more matches?
我有一个文件,其文本看起来像
{\o H}{\o e}{\o l}{\o l}{\o o} {\o W}{\o o}{\o r}{\o l}{\o d}
我想让文字看起来像这样
{\o Hello} {\o World}
可能有多种工具可以用来解决这个问题,但我正在尝试使用 vim 替换。到目前为止,我有
:%s/{\o \(.\{-}\)}{\o \(.\{-}\)}/{\o }/g
这里的图案是
.\{-}
匹配部分字符,非贪心
{\o .\{-}}
匹配正则表达式字符串 {\o .*}
但与 .*
不匹配
和 \( ... \)
为反向引用创建捕获组。
当我 运行 这个替换一次时,我得到
{\o He}{\o ll}{\o o} {\o Wo}{\o rl}{\o d}
我可以运行这个命令再执行两次得到
{\o Hell}{\o o} {\o Worl}{\o d}
然后
{\o Hello} {\o World}
但如果有一种方法可以用一个命令做到这一点,我真的很高兴,即告诉 vim 替换继续传递文件,直到没有更多匹配项为止。在我看来,这应该是可能的。
有谁知道我需要添加什么魔法才能实现这一目标?看起来没有实现这一目标的标志。也许我不知道标签的一些技巧?
子替换表达式方法
您可以使用子替换表达式 \=
,在 :s
的替换部分内执行第二次替换
:%s/\({\o \S}\)\+/\='{\o '.substitute(submatch(0), '{\o \(\S\)}', '', 'g').'}'/g
基本思路是捕获 "word",例如{\o H}{\o e}{\o l}{\o l}{\o o}
,然后对捕获的"word"、submatch(0)
进行第二次替换。第二次替换将通过 substitute(submatch(0), '{\o \(\S\)}', '', 'g')
删除开头的 {\o
和结尾的 }
。这只留下字母,在本例中为 Hello
。一旦从单词中提取出每个字母,我们就会在开头 {\o
和尾随 }
.
中添加回去
如需更多帮助,请参阅:
:h :s
:h sub-replace-expresion
:h substitute(
:h submatch(
:h literal-string
:h /\S
两次换人
您也可以使用 2 个单独的替换。一个删除所有 {\o
和 }
。另一个替换将把它们加回去,但这次是逐字的。
:%s/{\o \(.\)}//g
:%s/\S+/{\o &}/g
假设您没有将此文本与不应采用此格式的其他文本混合在一起,这可以说是一种更简单的方法。
您也可以使用 |
:
在一个命令中完成此操作
:%s/{\o \(.\)}//g|%s/\S+/{\o &}/g
这里有一个更简单的解决方案:
递归宏。递归宏的基本思想是,一个宏会调用自身直到发生错误。当您 运行 替换命令并且没有匹配项时,这将引发错误。所以这是你需要做的基本布局。
清除宏'q'。这是必不可少的,这样它就不会在第一个 运行 通过时做任何奇怪的事情。您可以使用
qqq
或
:let @q=""
两者都有效。
开始录制。这只是:
qq
运行 你的替代命令,然后调用宏。这将是
:%s/{\o \(.\{-}\)}{\o \(.\{-}\)}/{\o }/g<cr>@q
因为 @q
是 运行 宏的命令。 这不会在您录制时执行任何操作,因为您已经清除了寄存器'q'。最后,
停止录制,调用宏。
q@q
这将循环您刚才按下的一组击键,直到没有匹配项为止。
综合起来:
qqqqq:%s/{\o \(.\{-}\)}{\o \(.\{-}\)}/{\o }/g<cr>@qq@q
开头是 5 'q' 秒。您还可以从命令行分配寄存器 'q',其中:
:let @q=':%s/{\o \(.\{-}\)}{\o \(.\{-}\)}/{\o }/g<cr>@q'
然后点击
<cr>@q
作为旁注,我强烈推荐dedicated vim-site。
我有一个文件,其文本看起来像
{\o H}{\o e}{\o l}{\o l}{\o o} {\o W}{\o o}{\o r}{\o l}{\o d}
我想让文字看起来像这样
{\o Hello} {\o World}
可能有多种工具可以用来解决这个问题,但我正在尝试使用 vim 替换。到目前为止,我有
:%s/{\o \(.\{-}\)}{\o \(.\{-}\)}/{\o }/g
这里的图案是
.\{-}
匹配部分字符,非贪心
{\o .\{-}}
匹配正则表达式字符串 {\o .*}
但与 .*
和 \( ... \)
为反向引用创建捕获组。
当我 运行 这个替换一次时,我得到
{\o He}{\o ll}{\o o} {\o Wo}{\o rl}{\o d}
我可以运行这个命令再执行两次得到
{\o Hell}{\o o} {\o Worl}{\o d}
然后
{\o Hello} {\o World}
但如果有一种方法可以用一个命令做到这一点,我真的很高兴,即告诉 vim 替换继续传递文件,直到没有更多匹配项为止。在我看来,这应该是可能的。
有谁知道我需要添加什么魔法才能实现这一目标?看起来没有实现这一目标的标志。也许我不知道标签的一些技巧?
子替换表达式方法
您可以使用子替换表达式 \=
,在 :s
:%s/\({\o \S}\)\+/\='{\o '.substitute(submatch(0), '{\o \(\S\)}', '', 'g').'}'/g
基本思路是捕获 "word",例如{\o H}{\o e}{\o l}{\o l}{\o o}
,然后对捕获的"word"、submatch(0)
进行第二次替换。第二次替换将通过 substitute(submatch(0), '{\o \(\S\)}', '', 'g')
删除开头的 {\o
和结尾的 }
。这只留下字母,在本例中为 Hello
。一旦从单词中提取出每个字母,我们就会在开头 {\o
和尾随 }
.
如需更多帮助,请参阅:
:h :s
:h sub-replace-expresion
:h substitute(
:h submatch(
:h literal-string
:h /\S
两次换人
您也可以使用 2 个单独的替换。一个删除所有 {\o
和 }
。另一个替换将把它们加回去,但这次是逐字的。
:%s/{\o \(.\)}//g
:%s/\S+/{\o &}/g
假设您没有将此文本与不应采用此格式的其他文本混合在一起,这可以说是一种更简单的方法。
您也可以使用 |
:
:%s/{\o \(.\)}//g|%s/\S+/{\o &}/g
这里有一个更简单的解决方案:
递归宏。递归宏的基本思想是,一个宏会调用自身直到发生错误。当您 运行 替换命令并且没有匹配项时,这将引发错误。所以这是你需要做的基本布局。
清除宏'q'。这是必不可少的,这样它就不会在第一个 运行 通过时做任何奇怪的事情。您可以使用
qqq
或
:let @q=""
两者都有效。
开始录制。这只是:
qq
运行 你的替代命令,然后调用宏。这将是
:%s/{\o \(.\{-}\)}{\o \(.\{-}\)}/{\o }/g<cr>@q
因为
@q
是 运行 宏的命令。 这不会在您录制时执行任何操作,因为您已经清除了寄存器'q'。最后,停止录制,调用宏。
q@q
这将循环您刚才按下的一组击键,直到没有匹配项为止。
综合起来:
qqqqq:%s/{\o \(.\{-}\)}{\o \(.\{-}\)}/{\o }/g<cr>@qq@q
开头是 5 'q' 秒。您还可以从命令行分配寄存器 'q',其中:
:let @q=':%s/{\o \(.\{-}\)}{\o \(.\{-}\)}/{\o }/g<cr>@q'
然后点击
<cr>@q
作为旁注,我强烈推荐dedicated vim-site。