在Vim中合并多行(两个块)

我想在Vim中合并两行a..bn..ma..b添加到a..b行。 如果你喜欢伪代码的解释: [a[i] + b[i] for i in min(len(a), len(b))]

例:

 abc def ... 123 45 ... 

应该成为

 abc123 def45 

有没有一个很好的方法来做到这一点,而不是手动复制和粘贴?

你当然可以用一个复制/粘贴(使用块模式select)来做所有这些,但是我猜这不是你想要的。

如果你想用Ex命令来做到这一点

 :5,8del | let l=split(@") | 1,4s/$/\=remove(l,0)/ 

将会改变

 work it make it do it makes us harder better faster stronger ~ 

 work it harder make it better do it faster makes us stronger ~ 

更新:与这许多upvotes答案值得更彻底的解释。

在Vim中,可以使用pipe道字符( | )来链接多个Ex命令,所以上面的内容相当于

 :5,8del :let l=split(@") :1,4s/$/\=remove(l,0)/ 

许多Ex命令都接受一系列的行作为前缀参数 – 在上面的例子中, del和前面的5,8指定了命令操作的行。

del删除给定的行。 它可以采用一个寄存器参数,但是当没有给出时,它会将行转移到未命名的寄存器@" ,就像正常模式下的删除一样, let l=split(@")然后将删除的行分割成一个列表,使用默认的分隔符:空格。 要在删除的行中有空格的input正常工作,如:

 more than hour our never ever after work is over ~ 

我们需要指定一个不同的分隔符,以防止“work is”被分成两个列表元素: let l=split(@","\n")

最后,在replaces/$/\=remove(l,0)/ ,我们用expression式remove(l,0)的值replace每行的结尾( $ remove(l,0)remove(l,0)改变列表l ,删除并返回其第一个元素。 这让我们以我们阅读的顺序来replace已删除的行。 我们可以用remove(l,-1)来代替相反的顺序。

通过结合:global:move:join命令,可以获得一个优雅和简洁的Ex命令解决问题。 假设第一行代码行从缓冲区的第一行开始,并且光标位于第二行代码的第一行之前的那一行,那么命令如下。

 :1,g/^/''+m.|-j! 

有关所用技术的详细说明,请参阅我给“ Vim paste -d”行为开箱的问题的答案 。 “

要join行的块,您必须执行以下步骤:

  1. 去第三行: jj
  2. 进入视觉模块模式: CTRL-v
  3. 将光标定位到行的末尾(对于不同长度的行很重要): $
  4. 转到最后: CTRL-END
  5. 切块: x
  6. 转到第一行的末尾: kk$
  7. 粘贴块在这里: p

这个运动并不是最好的(我不是专家),但它的工作原理就像你想的那样。 希望有一个更短的版本。

这是先决条件,所以这种技术运作良好:

  • 起始块的所有行(在问题abcdef中的示例中)具有相同的XOR长度
  • 起始块的第一行是最长的,你不关心在其间的额外空间) 异或
  • 起始块的第一行并不是最长的,而且你还有额外的空间。

下面是我该怎么做(光标在第一行):

 qama:5<CR>y$'a$p:5<CR>dd'ajq3@a 

你需要知道两件事情:

  • 第二组第一行开始的行号(在我的情况下是5)和
  • 每组中的行数(在我的例子中是3)。

以下是发生了什么事情:

  • qalogging到下一个q所有内容到一个“缓冲区”中。
  • ma在当前行上创build一个标记。
  • :5<CR>进入下一个组。
  • 其余的部分是y$
  • 'a回报的标志,设置较早。
  • $p在行尾。
  • :5<CR>返回到第二组的第一行。
  • dd删除它。
  • 'a回报的标志。
  • jq下降一行,停止录音。
  • 3@a重复每行的行动(在我的情况下是3)

正如其他地方所提到的,区块select是要走的路。 但是你也可以使用任何变体:

:!tail -n -6 % | paste -d '\0' % - | head -n 5

这种方法依赖于UNIX命令行。 创build了paste实用程序来处理这种行合并。

 PASTE(1) BSD General Commands Manual PASTE(1) NAME paste -- merge corresponding or subsequent lines of files SYNOPSIS paste [-s] [-d list] file ... DESCRIPTION The paste utility concatenates the corresponding lines of the given input files, replacing all but the last file's newline characters with a single tab character, and writes the resulting lines to standard output. If end-of-file is reached on an input file while other input files still contain data, the file is treated as if it were an endless source of empty lines. 

示例数据与rampion相同。

 :1,4s/$/\=getline(line('.')+4)/ | 5,8d 

我不会认为这太复杂。 我只是设置virtualedit
:set virtualedit=all
select块123和全部下面。
把它放在第一列之后:

 abc 123 def 45 ... ... 

并删除到1个空格之间的多个空格:

 :%s/\s\{2,}/ /g 

我会用复杂的重复:)

鉴于这种:

 aaa bbb ccc AAA BBB CCC 

将光标置于第一行的第一个“a”处,按下:

 qq}jdd''$pkJj0q 

然后按@q (随后可以使用@@ )按需要多次。

你最终应该:

 aaaAAA bbbBBB cccCCC 

(加一个换行符。)

可以有很多方法来完成这个。 我将使用以下两种方法之一合并两个文本块。

假设第一块在第一行,第二块从第十行开始,光标在第一行的初始位置。

(\ n表示按下回车键。)

 1. abc def ghi 10. 123 456 789 

用macros使用命令:复制,粘贴和连接。

qaqqa:+ 9Y \ npkJjq2 @ a10G3dd

使用命令的macros在第n行号处移动一行并join。

qcqqc:10m。\ nkJjq2 @ c