【问题标题】:Vim: How to apply external command only to lines matching patternVim:如何仅将外部命令应用于匹配模式的行
【发布时间】:2013-11-18 12:43:55
【问题描述】:

我最喜欢的两个 Vim 功能是能够将标准运算符应用于匹配正则表达式的行,以及通过外部命令过滤选择或范围的行的能力。但是这两个想法可以结合起来吗?

例如,我有一个用作实验室笔记本的文本文件,其中包含不同日期的笔记,并用一行破折号分隔。我可以用:% g/^-/d 之类的东西删除所有虚线。但是假设我想调整所有实际文本行的大小,而不触及那些虚线。

对于单个段落,这类似于{!}fmt。但这如何应用于所有非破折号段落?当我尝试看起来合乎逻辑的事情时,只需将这两个与:% v/^-/!fmt 链接在一起,那是行不通的。 (其实Vim好像崩溃了……)

有没有办法将这两个想法联系起来,并且只将匹配模式的行(不)传递给像fmt这样的外部命令?

【问题讨论】:

  • 我不认为 Vim 崩溃了,我发现 fmt 的结果更有可能产生更多行,因此最终会无休止地递归(并构建一个巨大的文件)
  • 不要将% 范围与:g:v 一起使用,默认情况下它们适用于整个缓冲区。
  • @Sarah 你说得对,Vim 没有在这里崩溃,但原因是提问者使用了 :!fmt 没有范围。没有范围 :!fmt 从标准输入读取。没有崩溃,fmt 只是在等待输入。

标签: regex vim


【解决方案1】:

考虑:global 命令的工作原理。

:global(和:v)两次通过缓冲区,

  • 首先标记匹配的每一行,
  • 然后在标记的行上执行给定的命令。

因此,如果您可以提出一个命令(无论是 Ex 命令还是命令行工具)以及可应用于每个匹配行(和范围)的关联范围,您就有了赢家。

例如,假设您的文本是软换行的,并且您的段落只是以减号开头的行,以下是重新格式化段落的方法:

:v/^-/.!fmt -72

这里我们使用了.“当前行”范围,因此通过fmt过滤了每个匹配的行。更复杂的范围也有效。例如,如果您的文本是硬换行的,并且段落被定义为“从以减号开始的行,直到下一个空白行”,您可以改用:

:g/^-/.,'}!fmt -72

帮助主题:

【讨论】:

    【解决方案2】:

    一种方法可能是将命令应用于与模式“不只包含破折号”匹配的行

    我会尝试的解决方案类似于(未测试):

    :g/\v^(-+)@!/normal V!fmt
    

    编辑我正在做一些实验,我认为递归宏应该适合你

    首先设置 nowrapscan:

    set nowrapscan
    

    为了防止递归宏执行超出您的预期。

    然后你进行搜索:

    /\v^(-+)@!
    

    测试按下np 是否适用于您的模式并在需要时对其进行调整

    之后,开始录制宏

    qqn:.!awk '{print $2}'^M$
    

    在这种情况下,我以 awk 为例 .! 表示使用外部程序过滤当前行 然后要使宏递归,只需将字符串'@q' 附加到寄存器@q

    let @q .= '@q'
    

    然后移动到缓冲区的开头以应用递归宏并进行修改:

    gg@q
    

    然后你就完成了。希望这会有所帮助

    【讨论】:

      猜你喜欢
      • 2013-08-09
      • 2017-02-02
      • 2016-04-29
      • 2011-09-14
      • 2013-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多