Vim:删除光标周围的空行

12

假设我正在编辑以下文档(* = 光标):

Lions
Tigers


Kittens
Puppies


*


  Humans

我可以使用什么序列来删除周围的空白,以便只剩下:

Lions
Tigers


Kittens
Puppies
*
  Humans

注意:我正在寻找一个处理任意数量空行的答案,而不仅是这种情况的答案。

编辑1:行号未知,我只想影响我的光标所在的范围。

编辑2:编辑示例以显示我需要保留边缘上的前导空格

谢谢


你是否正在寻找脚本/命令的解决方案?如果手动操作太容易了,最好提供更多信息,比如为什么光标在那里? - Billy Chan
当前行(光标下方)是否总是空行? - Kent
@Billy Chan,除非你的手动方式可以使用一个通用映射完成,否则我不同意它是“太容易”的说法。光标在那里只是因为它最终停留在那里 :) - Dane O'Connor
我看不出光标出现的模式,这使得找出通用映射变得困难。 - Billy Chan
@BillyChan 我只是在文档中移动光标。可能我已经<C-D>进入了空白区域。 - Dane O'Connor
我不明白光标在那里为什么很重要。原帖作者想要删除光标上方和下方所有连续的空行(或者可能是所有空格)。这似乎非常合理。 - jahroy
6个回答

13

简单易懂。在普通模式下,dipO<Esc>即可实现。

解释:

  • dip 在一个空白行上删除它及其相邻的所有空白行。
  • O<Esc> 打开一个新的空行,然后返回普通模式。

更简洁的方式是,如 @Lorkenpeist 所建议的,cip<Esc> 可将这两个步骤合并为一步。


1
迄今为止最干净、最直观的解决方案。+1 - David Cain
只要您有一个以上的空格,vipJ 就可以工作,并且它避免了进入插入模式。 - Peter Rincker
5
太棒了!稍微更好一点:cip<Esc> - Lorkenpeist
@Lorkenpeist 好的,是啊,我为什么没想到呢?! - glts
最好的部分是 cip<esc> 可以用 . 重复!尽管如果我有一个完整的文件需要挤压空格,我仍然会使用 :v/./,//-j - Peter Rincker
+1 这是对问题的简短而干净的回答。@Lorkenpeist 也许你可以考虑接受它。 - Kent

7
一种可能的解决方案是使用:join命令与范围一起使用:
:?.?+1,/./-1join!

说明:

  • [range]join! 将连接一组 [range] 的行。 ! 表示不插入任何额外的空格。
  • 起始点是向后搜索到第一个字符,然后向下 1 行,?.?+1
  • 由于 +1 中的 1 可以被假定,因此可以缩写为 ?.?+
  • 结束点是向前搜索到下一个字符,然后向上 1 行,/./-1
  • 与之前相同,1 可以被假定,因此为 /./-
  • 由于我们只是向前搜索相同的模式,因此可以省略模式。 //-
  • 命令 :join 可以简写为 :j

最终缩短的命令:

:?.?+,//-j!

以下是一些相关的命令,可能会很有用:
1) 删除所有空行:
:g/^$/d
:v/./d
2) 将所有空行压缩成只有一个空行:
:v/./,//-j
更多帮助请参见:
:h :j
:h [range]
:h :g
:h :v

1
е°Ҫз®Ўc/dipзҡ„зӯ”жЎҲжӣҙйҖӮеҗҲиҝҷдёӘй—®йўҳпјҢдҪҶдҪ еҗ‘еҗҺжҗңзҙўзҡ„?.?д№ҹеҫҲеҘҪгҖӮжҲ‘жІЎжғіеҲ°гҖӮ+1 - Kent

3

简短回答: ()V)kc<esc>

在正常模式下,如果您键入(),光标将移动到第一行空行。 (将光标移动到上一个非空白行块的开头,)将光标移动到结束位置(具体而言,是在该块后面的第一行空行)。然后,简单的d)将删除所有文本,直到下一个非空白行的开头。因此,完整的序列是()d)

编辑:你是对的,那会删除下一行非空白字符开始的空格。而不是d)尝试使用V)kdV 将您置于可视化行模式中,)跳转到第一行非空白行(跳过行开头的空格),k将光标向上移动一行。此时,您已选择所有空行,因此d删除了选择。

最后,键入大写字母 O(capital O)以创建一个新的空行来替换您删除的行。或者,用c<Escape>替换dO<Escape>可以减少一个按键,因此整个序列将是()V)kc<Esc>


OP 还想删除光标上方的所有空行。 - jahroy
@jahroy 我认为这个序列实际上就是这样做的。现在只是删除了一些过多的内容。 - Dane O'Connor
2
这似乎会删除光标位置上方和下方的所有空行,包括光标所在的那一行。 - jahroy
@Conner kkd会在只有一行空白的情况下删除非空格字符。 - Lorkenpeist
@Peter 太棒了,但是它对于单个空白行也不起作用。我真的希望那个能够运行 :( - Lorkenpeist
显示剩余4条评论

1

在更新后的问题中,这些答案不相关:

这可能不是你想听到的答案,但我会利用范围。查看第一个空行的行号(例如为55),以及倒数第二个空行的行号(也许是67)。然后只需执行:55,67d

或者,也许你只想在整个文件中有一个空行。在这种情况下,你可以匹配任何出现一行或多行空行的情况,并将其替换为一个空行。

:%s/\(^$\n\)\+/\r/

这个答案可行:

如果您只想使用普通模式,可以搜索最后一行上的任何内容。例如,

/.<Enter>kkVNjd

谢谢Conner。是的,这不是我要找的。我不知道行号,而且我希望有更多的空白。我编辑了问题以使其更具体。 - Dane O'Connor
如果只有一行空白行,这并不起作用,实际上会删除一些真正的文本。 - Lorkenpeist

1
我没有进行过太多测试,但它应该对你的示例起作用。可能有更优雅的解决方案。
function! DelWrapLines()
    while match(getline('.'),'^\s*$')>=0
        exe 'normal kJ'
    endwhile
    exe 'silent +|+,/./-1d|noh'
    exe 'normal k'
endfunction

将其源代码化并尝试使用:call DelWrapLines()

这实际上导致了vim卡住。你能详细说明一下以帮助排除故障吗? - Dane O'Connor
@thedeeno 我在办公室测试过了,可以正常工作。很奇怪。我现在正在回家的路上,无法进行进一步的测试。如果有打扰到你,非常抱歉。我回到家后会再次检查它。 - Kent

0

我知道这个问题已经解决了,但是我刚在“sed & awk, 2nd Ed.”(O'Reilly)中找到了一个很好的解决方案,我觉得值得分享。它完全不使用vim,而是使用sed。这个脚本将替换所有一个或多个空行的实例(假设这些行中没有空格),并用一个单独的空行代替。在命令行上:

sed '/ˆ$/{
N
/ˆ\n$/D
}' myfile

请记住,sed 实际上并不编辑文件,而是将编辑后的行打印到标准输出。您可以将此输入重定向到文件:
sed '/ˆ$/{
N
/ˆ\n$/D
}' myfile > tempfile

注意,如果您尝试直接将其写入myfile,它将删除文件的所有内容,这显然不是您想要的!在将输出写入tempfile后,您只需执行mv tempfile myfile,就可以完成了!所有多个空行的实例都将替换为单个空行。

更好的方法:

cat -s myfile > temp
mv temp myfile

猫很棒,对吧?

最好的方法:

如果你想在vim中完成它,你可以使用vim方便的特性,在vim内执行shell命令替换多个空行实例为单个空行。

:%!cat -s

只需要这样做,你的整个文件就会被重新格式化得很好!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接