如果没有更多匹配,我如何让vim替换重复?

时间:2016-08-23 18:17:27

标签: regex vim substitution

我的文件看起来像

{\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 \1\2}/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替换继续传递文件,直到没有更多的匹配。在我看来,这应该是可能的。

有谁知道我需要添加什么魔法才能实现这一目标?它看起来不像有一个标志可以实现这一点。也许我不知道标签的一些技巧?

2 个答案:

答案 0 :(得分:5)

子替换表达式方法

您可以使用子替换表达式\=:s的替换部分内执行第二次替换

:%s/\({\\o \S}\)\+/\='{\o '.substitute(submatch(0), '{\\o \(\S\)}', '\1', 'g').'}'/g

基本思想是捕获“单词”,例如{\o H}{\o e}{\o l}{\o l}{\o o},然后对捕获的“单词”submatch(0)进行第二次替换。第二次替换将通过{\o删除起始}和尾随substitute(submatch(0), '{\\o \(\S\)}', '\1', 'g')。这只留下了这个例子中的字母Hello。从单词中提取每个字母后,我们会在起始{\o和尾随}中添加。

如需更多帮助,请参阅:

:h :s
:h sub-replace-expresion
:h substitute(
:h submatch(
:h literal-string
:h /\S

两次替换

您还可以使用2个单独的替换。一个用于删除所有{\o}。另一个替换会将它们重新添加回来,但这次是逐字的。

:%s/{\\o \(.\)}/\1/g
:%s/\S+/{\\o &}/g

这可以说是一种更简单的方法,假设您没有将此文本与其他不应采用此格式的文本混合在一起。

您也可以使用|

在一个命令中执行此操作
:%s/{\\o \(.\)}/\1/g|%s/\S+/{\\o &}/g

答案 1 :(得分:5)

这是一个更简单的解决方案:

递归宏。递归宏的基本思想是在发生错误之前调用自身的宏。当您运行替换命令并且没有匹配项时,这将引发错误。所以这是你需要做的基本布局。

  1. 清除宏' q'。这是必不可少的,因此在第一次运行时它不会做任何奇怪的事情。您可以使用

    执行此操作
    qqq
    

    :let @q=""
    

    任何一个都有效。

  2. 开始录制。这只是:

    qq
    
  3. 运行您的替换命令,然后调用宏。这将是

    :%s/{\\o \(.\{-}\)}{\\o \(.\{-}\)}/{\\o \1\2}/g<cr>@q
    

    由于@q是运行宏的命令。 当您录制时,这不会做任何事情,因为您已经清除了注册&#39; q&#39;。最后,

  4. 停止录制,然后调用宏。

    q@q
    

    这将循环你刚刚按下的按键组,直到没有匹配。

  5. 把这一切放在一起:

    qqqqq:%s/{\\o \(.\{-}\)}{\\o \(.\{-}\)}/{\\o \1\2}/g<cr>@qq@q
    

    开头的5&#39; q。你也可以分配寄存器&#39; q&#39;从命令行,使用:

    :let @q=':%s/{\\o \(.\{-}\)}{\\o \(.\{-}\)}/{\\o \1\2}/g<cr>@q'
    

    然后点击

    <cr>@q
    

    作为旁注,我强烈推荐dedicated vim-site