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

xen*_*aii 4 regex vim substitution

我有一个文本看起来像

{\o H}{\o e}{\o l}{\o l}{\o o} {\o W}{\o o}{\o r}{\o l}{\o d}
Run Code Online (Sandbox Code Playgroud)

我想让文字看起来像这样

{\o Hello} {\o World}
Run Code Online (Sandbox Code Playgroud)

我可以使用多种工具来解决这个问题,但我正在尝试使用vim替换.到目前为止,我有

:%s/{\\o \(.\{-}\)}{\\o \(.\{-}\)}/{\\o \1\2}/g
Run Code Online (Sandbox Code Playgroud)

这里的模式是

.\{-} 匹配一些人物,不贪心

{\\o .\{-}}匹配正则表达式字符串{\o .*}但非贪婪的.*

\( ... \)创建用于反向引用的捕获组.

当我进行一次替换时,我得到了

{\o He}{\o ll}{\o o} {\o Wo}{\o rl}{\o d}
Run Code Online (Sandbox Code Playgroud)

可以再运行这个命令两次

{\o Hell}{\o o} {\o Worl}{\o d}
Run Code Online (Sandbox Code Playgroud)

然后

{\o Hello} {\o World}
Run Code Online (Sandbox Code Playgroud)

但我真的很喜欢,如果有一种方法可以用一个命令来做到这一点,即告诉vim替换继续传递文件,直到没有更多的匹配.在我看来,这应该是可能的.

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

Pet*_*ker 5

子替换表达方法

您可以使用sub-replace-expression \=来在的替换部分内执行第二次替换:s

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

基本思想是例如捕获一个“单词”,{\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
Run Code Online (Sandbox Code Playgroud)

两次替换

您也可以使用2个单独的替换项。一个删除所有{\o}。其他替换将重新添加它们,但这一次是明智的。

:%s/{\\o \(.\)}/\1/g
:%s/\S+/{\\o &}/g
Run Code Online (Sandbox Code Playgroud)

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

您还可以使用|以下命令在一个命令中执行此操作:

:%s/{\\o \(.\)}/\1/g|%s/\S+/{\\o &}/g
Run Code Online (Sandbox Code Playgroud)


DJM*_*hem 5

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

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

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

    qqq
    
    Run Code Online (Sandbox Code Playgroud)

    要么

    :let @q=""
    
    Run Code Online (Sandbox Code Playgroud)

    两个都有效.

  2. 开始录制.这只是:

    qq
    
    Run Code Online (Sandbox Code Playgroud)
  3. 运行您的替换命令,然后调用宏.这将是

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

    因为@q是运行宏的命令.在录制时这不会做任何事情,因为你已经清除了注册'q'.最后,

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

    q@q
    
    Run Code Online (Sandbox Code Playgroud)

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

把这一切放在一起:

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

那是开头的5'q.您还可以从命令行分配寄存器'q',其中包括:

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

然后点击

<cr>@q
Run Code Online (Sandbox Code Playgroud)

作为旁注,我强烈推荐一个专用的vim网站.