【问题标题】:How to delete every other line in Vim?如何删除 Vim 中的每一行?
【发布时间】:2009-12-22 14:35:55
【问题描述】:

我想从 Vim 缓冲区中删除每隔一行,从第二个开始,即第 2、4、6 行等。例如,如果缓冲区的内容是:

aaa
bbb
ccc
ddd
eee
fff

那么,在删除所需的行之后,它应该变成:

aaa
ccc
eee

哪些 Vim 命令可用于自动执行此操作?

【问题讨论】:

标签: vim


【解决方案1】:

完成任务的一种优雅(高效)的方法是调用 :delete 命令(参见:help :d)用于+ 行范围(与.+1 相同) 寻址当前行之后的行(请参阅:help {address}),on 每一行(参见:help /^)使用:global 命令(参见:help :g):

:g/^/+d

【讨论】:

  • 为什么这个答案没有得到更多的支持?这是如此干净和简单。或者,您可以删除第一行并运行上述命令以删除所有奇数行。
  • @Usagi:谢谢!我对此也有同样的感觉。是的,你完全正确,:1d|g/^/+d 删除了奇数行。
  • 对不起,但没有解释该命令如何执行所需行为,我不会赞成它,而是更喜欢接受的答案,因为我了解它如何实现目标。这就是授人以鱼和教他如何钓鱼的区别。
  • 我不知道,这个答案让我出去学习用 :g 命令钓鱼(也就是说,它让我在谷歌上搜索这个页面 - vim.wikia.com/wiki/Power_of_g)。
  • 如果你用鱼打他......但是,嘿,接受的答案也没有解释。我认为复制全局命令文档没有任何意义。我忘记了如何使用全局命令(尽管我是一个古老的 vi 人)并且发现这个页面在谷歌上搜索。最有帮助。
【解决方案2】:

您可以为此使用宏。执行以下操作。

  • 以命令模式启动。
  • gg 转到文件的开头。
  • 请按qq
  • 点击向下箭头,然后按dd
  • 请按q
  • 10000@q

PS:要进入命令模式,只需按几次 Escape。

【讨论】:

  • 当然,假设您的文件少于 20,000 行 :-)
  • 其实你错了迈克尔。这可以完美地工作,因为 VI 将在宏到达文件末尾时立即停止运行。您可以使用上面的示例非常轻松地进行尝试。
  • 嗯,就像任何宏一样,您需要在第一次正确处理它,但之后您只需键入 10000@q 即可应用于任何文件。无论哪种方式,我相信这只是品味问题,所以我绝对不会开始一场哲学辩论。 :)
  • 我更喜欢使用“宏”。使用宏,您“描述”您将如何解决一项特定任务并让 VIM 为您重复它。 RUI,我更喜欢使用“j”而不是箭头键。
  • :g/^/+d from user stackoverflow.com/users/254635/ib (bellow) 是解决这个问题的更优雅的方法。
【解决方案3】:

我们可以使用:normal(或:norm)命令来执行 jdd 正常模式命令:

:%norm jdd

来源: zzapper 的Best of Vim Tips 页面。

【讨论】:

  • 这个答案没有得到足够的关注,可能是因为这里和链接的、凌乱的备忘单上都没有解释。 norm 命令运行与它后面的字母等效的正常模式命令。所以这里运行 j 向下移动一行, dd 删除它。这可以通过在这种情况下添加更多的 'j' 推广到第 X 行。
  • 而 % 是 1,$ 的简写(从第 1 行到最后执行以下命令)
  • 如果您想删除奇数行,我很想知道为什么 %norm ddj 不起作用。
【解决方案4】:
:map ^o ddj^o
^o

这里 ^ 代表 CTRL。 递归宏每两行删除一行。选择好你的第一行就完成了。

【讨论】:

    【解决方案5】:

    来自vim mail archive

    :let i=1 | while i <= line('$') | if (i % 2) | exe i . "delete" | endif | let i += 1 | endwhile
    

    (要在vim命令行的一行输入,将删除第1、3、5、7行,...)

    【讨论】:

    • 那我更喜欢!perl -ne 'print unless $. % 2' :-)
    • 而且,Alex,我肯定更喜欢我的解决方案而不是你的解决方案,但是这个值得考虑,因为这是这里唯一只使用 vim 本身的合理解决方案。
    • 宏方式要容易得多。
    • +1 因为if (expression) 的灵活性,它也适用于每三行等。
    【解决方案6】:

    您始终可以通过 shell 命令进行管道传输,这意味着您可以使用任何您喜欢的脚本语言:

    :%!perl -nle 'print if $. % 2'
    

    (或使用“除非”而不是“如果”,具体取决于您想要的行)

    【讨论】:

    • 你不需要 -l 切换到 Perl ......另外,我想说 awk 比 Perl 更普遍,尽管现在它并没有那么多,并且可以更短::%!awk NR\%2,或 :%!awk 1-NR\%2 用于其他行。
    【解决方案7】:
    :%!awk -- '++c\%2'
    

    或者

    :%!awk -- 'c++\%2'
    

    取决于你想淘汰哪一半。

    【讨论】:

    • 嗯,为什么不使用现有的NR 变量?
    • 对。因为我忘记了。 ;-) 但实际上,NR 的“正确”变体会更长。而且不会有两个漂亮的对应物。
    • :%!awk NR\%2:%!awk 1-NR\%2,正如我在另一条评论中发布的那样。几乎不会再长了。
    • 1-NRc++ 长。是的,我知道这是一个角色。就像我说的——真正的原因是我忘记了。反正,看来这里的人不欣赏 awk 的美。
    • 而且NR++c 短:)
    【解决方案8】:

    您可以像这样使用 Vim 自己的搜索和替换功能: 将光标放在第一行,然后在普通模式下输入:

    :.,/fff/s/\n.*\(\n.*\)/\1/g
    
    • .,/fff/ 是替换的范围。它的意思是“从这一行到匹配正则表达式 fff 的那一行(在本例中为最后一行)。
    • s/// 是替代命令。它查找一个正则表达式并用一个字符串替换它的每一次出现。末尾的g 表示只要不断找到正则表达式就重复替换。
    • 正则表达式\n.*\(\n.*\) 匹配一个换行符,然后是整行(.* 匹配除换行符之外的任意数量的字符),然后是另一个换行符和另一行。括号\(\) 会记录其中的表达式,因此我们可以稍后使用\1 使用它。
    • \1 插入分组的换行符和它后面的行,因为我们不希望下一行也消失 - 我们只希望替换机制通过它,所以我们不会在下一次替换时删除它。李>

    通过这种方式,您可以控制要删除的范围,而无需使用任何外部工具。

    【讨论】:

    • $ 而不是/fff/,用于文件结束,无论文件内容如何。
    【解决方案9】:

    作为另一种方法,如果你的 vim 支持它,你也可以使用 python。

    :py import vim; cb = vim.current.buffer; b = cb[:]; cb[:] = b[::2]
    

    b = cb[:] 临时将当前缓冲区中的所有行复制到bb[::2] 从缓冲区中获取每一行并将其分配给整个当前缓冲区 cb[:]。复制到b 是必要的,因为缓冲区对象似乎不支持扩展切片语法。

    这可能不是“vim 方式”,但如果你了解 python,可能更容易记住。

    【讨论】:

      【解决方案10】:

      删除奇数行(1、3、5、...):

      :%s/\(.*\)\n\(.*\)\n/\2\r/g
      

      删除偶数行 (2, 4, 6, ...):

      :%s/\(.*\)\n.*\n/\1\r/g
      

      搜索文本(形成第一行)后跟一个换行符和更多文本(形成第二行),然后是另一个换行符,并将上面的内容替换为第一个匹配项(奇数行)或第二个匹配项 (偶数行)后跟回车。

      【讨论】:

        【解决方案11】:

        调用 sed:

        :% !sed -e '2~2 d'
        
        ^^^^                  pipe file through a shell command
            ^^^^^^            the command is sed, and -e describes an expression as parameter
                    ^^^^^     starting with the second line, delete every second line
        

        【讨论】:

          【解决方案12】:

          解决方案

          你可以在 vim 中试试这个

          :1,$-1g/^/+1d
          

          编辑

          我会尽量说清楚(两部分)

          第一部分选择范围(:from,to
          第二部分动作(ddelete)

          • 从第一行到最后一行的范围 (:1,$-1)
          • 全局 (g) 删除 (+1d) 下一行

          你可以尝试移动到文件的第一行并执行:+1d你会看到下一行消失了

          我知道它很泥泞,但它是 vim 并且可以工作

          【讨论】:

          • 清如泥。谢谢!
          猜你喜欢
          • 2013-01-04
          • 2020-10-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-07-11
          • 1970-01-01
          • 1970-01-01
          • 2015-11-28
          相关资源
          最近更新 更多