如何在Vim中合并两个多行文本块?

如何在Vim中合并两个多行文本块?,vim,Vim,我想在Vim中合并两个行块,即从k行到l行,然后将它们附加到m行到n行。如果您喜欢伪代码解释:[line[k+i]+line[m+i]表示范围minl-k中的i,n-m+1] 比如说, abc def ... 123 45 ... 应该成为 abc123 def45 有没有一种不用逐行手动复制和粘贴的好方法?要连接行块,必须执行以下步骤: 转到第三行:jj 进入视觉块模式:CTRL-v 将光标锚定到对不同长度的线很重要的线的末端:$ 转到末尾:CTRL-end 剪切块:x 到第一行的末尾:

我想在Vim中合并两个行块,即从k行到l行,然后将它们附加到m行到n行。如果您喜欢伪代码解释:[line[k+i]+line[m+i]表示范围minl-k中的i,n-m+1]

比如说,

abc
def
...

123
45
...
应该成为

abc123
def45

有没有一种不用逐行手动复制和粘贴的好方法?

要连接行块,必须执行以下步骤:

转到第三行:jj 进入视觉块模式:CTRL-v 将光标锚定到对不同长度的线很重要的线的末端:$ 转到末尾:CTRL-end 剪切块:x 到第一行的末尾:kk$ 将块粘贴到此处:p 这项运动不是最好的,我不是专家,但它能像你想的那样工作。希望会有一个简短的版本

以下是使该技术工作良好的先决条件:

问题abc和def示例中起始块的所有行都具有相同的长度XOR 起始块的第一行是最长的,您不关心XOR之间的额外空格 起始块的第一行不是最长的,因此可以在末尾添加额外的空间。
您当然可以使用块模式选择通过单个复制/粘贴来完成所有这些,但我猜这不是您想要的

如果您只想使用命令执行此操作

将转变

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

更新:有这么多选票的答案应该得到更彻底的解释

在Vim中,您可以使用管道字符|来链接多个Ex命令,因此上述内容相当于

:5,8del
:let l=split(@")
:1,4s/$/\=remove(l,0)/
许多Ex命令接受一系列行作为前缀参数——在上述情况下,del前面的5,8和s///前面的1,4指定命令操作的行

del删除给定的行。它可以接受register参数,但如果没有给出参数,它会将行转储到未命名寄存器@,就像在正常模式下删除一样。让l=split@然后使用默认分隔符:空格将删除的行拆分为一个列表。要正确处理删除行中有空格的输入,请执行以下操作:

more than 
hour 
our 
never 
ever
after
work is
over
~
我们需要指定一个不同的分隔符,以防止工作被拆分为两个列表元素:let l=split@,\n


最后,在替换s/$/\=removel,0/中,我们用表达式removel,0的值替换每行$的末尾。removel,0更改列表l,删除并返回其第一个元素。这使我们能够按照读取顺序替换删除的行。我们可以使用removel,-1以相反的顺序替换删除的行。

以下是光标位于第一行时的操作方法:

qama:5<CR>y$'a$p:5<CR>dd'ajq3@a
你需要知道两件事:

在我的例子中,第二组的第一行从5开始的行号,以及 在我的示例中,每组中的行数为3。 下面是发生的事情:

qa将直到下一个q的所有内容记录到a中的缓冲区中。 ma在当前行上创建一个标记。 :5转到下一组。 y$猛拉队伍的其余部分。 'a返回到先前设置的标记。 $p粘贴在行的末尾。 :5返回第二组的第一行。 dd删除它。 "a回到了原点。 jq走下一行,停止录音。 3@a在我的案例中,对每行3重复该操作
正如在其他地方提到的,区块选择是一条出路。但您也可以使用以下任何变体:

:!尾部-n-6%|粘贴-d'\0'%-|头部-n 5

此方法依赖于UNIX命令行。创建粘贴实用程序是为了处理这种行合并

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.

通过以下步骤可以获得解决该问题的优雅简洁的Ex命令: 组合:全局、:移动和:连接命令。假设 第一行块从缓冲区的第一行开始,并且 光标位于第一个指针前面的行上 第二个块的行,命令如下

:1,g/^/''+m.|-j!
有关此技术的详细说明,请参阅
类似的问题“

我会使用复杂的重复:

鉴于此:

aaa
bbb
ccc

AAA
BBB
CCC
光标位于第一行时,按下以下按钮:

qa}jdd''pkJxjq
然后按@a,您可以根据需要多次使用@

您应该以以下方式结束:

aaaAAA
bbbBBB
cccCCC
加上一条新线

解释:

qa开始在一个文件中记录一个复杂的重复

}跳到下一个空行

jdd删除下一行

回到最后一次跳跃前的位置

p将删除的行粘贴到当前行下

kJ将当前行附加到上一行的末尾

x删除J在组合线之间添加的空间;如果需要空间,可以省略此项

j转到下一行

结束复杂的重复记录


之后,您将使用@a运行存储在a中的复杂重复,然后可以使用@重新运行上次运行的复杂重复。

示例数据与rampion的相同

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

我认为这不会太复杂。 我愿意 不要设置虚拟化 :set virtualdit=all 选择块123和下面的全部。 将其放在第一列之后:

abc    123
def    45
...    ...
并删除到1个空间之间的多个空间:

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

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

假设第一个块在第1行,第二个块从第10行开始,光标的初始位置在第1行

\n表示按回车键

1. abc
   def
   ghi        

10. 123
    456
    789
使用以下命令使用宏:复制、粘贴和连接

QQA:+9y\npkJjq2@a10G3dd

对于宏,使用命令在第n行号处移动一条线并连接

qqqc:10m\nkJjq2@c



那么…你想加入交替线吗?也就是说,你想把线x和连接x+2连接起来吗?不,我有两个独立的块。伪代码ish:[a[i]+b[i]对于minlena中的i,lenb]可以看到类似的问题和答案!哇,真有趣!我从来没有想过它会这样工作。这是因为abc和def的长度相同。块选择将保留已删除文本的缩进,因此,如果放置文本时光标位于短行上,则会在长行上的字母之间插入行,如果光标位于长行上,则会在短行上附加空格。事实上。。。有没有一种方法可以正确地使用块复制和粘贴?这毕竟是最简单的方法,尤其是当你因为某种原因无法在这里查找更复杂的方法时。比如@Izkata说,你会遇到在较长的行之间插入文本的问题。要解决这个问题,只需在第一行末尾添加更多空格,使其最长,然后粘贴文本块。完成后,将多个空格压缩为一个就很简单了:%s/\+///gset ve=all应该会有帮助,请参阅“嗯…”。。。我只需按一下回车键。它不会在两半之间插入空间。如果行上有一些尾随空格,如work it示例中所示,则仍然存在。您可以使用s/\s*$/而不是s/$/删除任何尾随空格。感谢您的解释:sil5,8del | let l=split@| sil1,4s/$/\=removel,0/| call histdel/,-1 | nohls似乎更好,因为它在运行后会清理搜索历史记录。它不会显示需要我按enter键的x more/less lines消息。如果你想要该答案的完整vim参考::help range,:help:d,:help:let,:help split,:help:s,:help:s\=,:help remove。确保像你这样的人想发布这样的答案,这就是我成为主持人的原因。好节目:如果前四句话后没有空格,就会出现问题。你必须在:5后按[Enter]键才能输入,否则将无法工作。我在gvim上。有没有办法在GVim中复制并粘贴该命令^V自动粘贴在插入模式下,这是有意义的,这是人们通常想要的,即使我目前处于正常模式。我试过:norm qama:5y$'a$p:5dd'ajq3@a但这似乎只执行q.ThiefMaster:Try:let@a=ma:5^My$'a$p:5^Mdd'aj | normal4@a,其中^M个字符是通过按CTRL-V然后按Enter键键入的。使用块选择并不是唯一的方法。这也不是最简单的一个。所需的类粘贴行为可以通过短Vim命令实现,如中所示。此外,我在windows上,因此解决方案将涉及打开到我的linux机器的SSH连接,并从编辑器粘贴到终端和终端。E16:无效范围-但它仍然有效。当删除1时,它不会出现错误。很遗憾,您不能接受多个答案-否则您的答案也会有一个绿色标记!很不错的!我不知道:移动和:加入!,也不包括范围参数的含义:help和范围修饰符的+和-的含义:help range。谢谢@ThiefMaster:该命令设计用于当两个要连接的行范围彼此相邻时使用,以便光标最初位于第一个块的最后一行,紧接着第二个块的第一行。请参阅链接的答案和问题。即使块中的行数不同,该命令也能按预期工作,尽管在这种情况下会发出错误消息。可以通过预编sil来抑制错误消息!@ib:我认为在这个答案中加入详细的解释也是个好主意。这个问题实际上不需要空格,我会做一些类似gvV:'
:%s/\s\{2,}/ /g
1. abc
   def
   ghi        

10. 123
    456
    789