在Vim中合并多行(两个块)
我想在Vim中合并两行a..b
第n..m
行a..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行的块,您必须执行以下步骤:
- 去第三行:
jj
- 进入视觉模块模式:
CTRL-v
- 将光标定位到行的末尾(对于不同长度的行很重要):
$
- 转到最后:
CTRL-END
- 切块:
x
- 转到第一行的末尾:
kk$
- 粘贴块在这里:
p
这个运动并不是最好的(我不是专家),但它的工作原理就像你想的那样。 希望有一个更短的版本。
这是先决条件,所以这种技术运作良好:
- 起始块的所有行(在问题
abc
和def
中的示例中)具有相同的XOR长度 - 起始块的第一行是最长的,你不关心在其间的额外空间) 异或
- 起始块的第一行并不是最长的,而且你还有额外的空间。
下面是我该怎么做(光标在第一行):
qama:5<CR>y$'a$p:5<CR>dd'ajq3@a
你需要知道两件事情:
- 第二组第一行开始的行号(在我的情况下是5)和
- 每组中的行数(在我的例子中是3)。
以下是发生了什么事情:
-
qa
logging到下一个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