我想在 Vim 中合并两行代码块,即,将行 k到 l并将它们附加到行m到 n。如果您更喜欢伪代码解释:[line[k+i] + line[m+i] for i in range(min(l-k, n-m)+1)]
.
例如,
abc
def
...
123
45
...
应该成为
abc123
def45
有没有一种很好的方法可以做到这一点,而无需逐行手动复制和粘贴?
我想在 Vim 中合并两行代码块,即,将行 k到 l并将它们附加到行m到 n。如果您更喜欢伪代码解释:[line[k+i] + line[m+i] for i in range(min(l-k, n-m)+1)]
.
例如,
abc
def
...
123
45
...
应该成为
abc123
def45
有没有一种很好的方法可以做到这一点,而无需逐行手动复制和粘贴?
您当然可以通过一次复制/粘贴(使用块模式选择)来完成所有这些,但我猜这不是您想要的。
如果您只想使用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
~
更新:有这么多赞成的答案值得更彻底的解释。
在 Vim 中,你可以使用竖线 ( |
) 来链接多个 Ex 命令,所以上面的等价于
:5,8del
:let l=split(@")
:1,4s/$/\=remove(l,0)/
许多 Ex 命令接受一系列行作为前缀参数 - 在上述情况下,5,8
before thedel
和1,4
before thes///
指定命令操作的行。
del
删除给定的行。它可以接受一个寄存器参数,但是当没有给出一个参数时,它会将行转储到未命名的寄存器中@"
,就像在正常模式下删除一样。 let l=split(@")
然后使用默认分隔符将删除的行拆分为一个列表:空格。要在已删除行中有空格的输入上正常工作,例如:
more than
hour
our
never
ever
after
work is
over
~
我们需要指定一个不同的分隔符,以防止“工作是”被分成两个列表元素:let l=split(@","\n")
.
最后,在替换中s/$/\=remove(l,0)/
,我们将每一行的末尾 ( $
) 替换为表达式的值remove(l,0)
。 remove(l,0)
改变 list l
,删除并返回它的第一个元素。这让我们可以按照阅读的顺序替换已删除的行。我们可以使用相反的顺序替换已删除的行remove(l,-1)
。
:global
结合, :move
, 和命令可以得到一个优雅简洁的 Ex 命令来解决这个问题:join
。假设第一个行块从缓冲区的第一行开始,并且光标位于第二个块的第一行之前的行,命令如下。
:1,g/^/''+m.|-j!
有关此技术的详细说明,请参阅我对类似问题的回答“<a href="https://stackoverflow.com/q/9658612/254635">如何实现“paste -d ''”开箱即用的行为在 Vim 中?”。
要加入线块,您必须执行以下步骤:
jj
CTRL-v
$
CTRL-END
x
kk$
p
该运动不是最好的(我不是专家),但它可以像您想要的那样工作。希望会有一个更短的版本。
这是先决条件,因此此技术效果很好:
abc
和def
)具有相同的长度XOR这是我的做法(光标在第一行):
qama:5<CR>y$'a$p:5<CR>dd'ajq3@a
你需要知道两件事:
这是发生了什么:
qa
将直到下q
一个的所有内容记录到a
.ma
在当前行上创建一个标记。:5<CR>
进入下一组。y$
猛拉其余的行。'a
返回标记,设置较早。$p
粘贴在行尾。:5<CR>
返回到第二组的第一行。dd
删除它。'a
返回标记。jq
下降一行,并停止录制。3@a
重复每一行的动作(在我的例子中是 3 个)如其他地方所述,块选择是要走的路。但您也可以使用以下任何变体:
:!tail -n -6 % | paste -d '\0' % - | head -n 5
此方法依赖于 UNIX 命令行。创建该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
我不认为让它太复杂。我只需在
( :set virtualedit=all
)
选择块 123 及以下所有内容上设置 virtualedit。
把它放在第一列之后:
abc 123
def 45
... ...
并删除到 1 个空格之间的多个空格:
:%s/\s\{2,}/ /g
我会使用复杂的重复:)
鉴于这种:
aaa
bbb
ccc
AAA
BBB
CCC
将光标放在第一行,按以下命令:
qa}jdd''pkJxjq
然后根据需要多次按@a
(您可以随后使用)。@@
你最终应该得到:
aaaAAA
bbbBBB
cccCCC
(加上换行符。)
解释:
qa
开始录制复杂的重复a
}
跳到下一个空行
jdd
删除下一行
''
回到最后一次跳跃前的位置
p
将删除的行粘贴到当前行下
kJ
将当前行附加到上一行的末尾
x
删除J
合并行之间添加的空格;如果你想要空间,你可以省略它
j
转到下一行
q
结束复杂的重复录音
之后,您将@a
用于运行存储在 中的复杂重复a
,然后您可以使用@@
重新运行上次运行的复杂重复。
可以有很多方法来实现这一点。我将使用以下两种方法中的任何一种来合并两个文本块。
假设第一个块在第 1 行,第二个块从第 10 行开始,光标的初始位置在第 1 行。
(\n 表示按回车键。)
1. abc
def
ghi
10. 123
456
789
使用以下命令使用宏:复制、粘贴和加入。
qaqqa:+9y\npkJjq2@a10G3dd
使用命令使用宏在第 n 行号处移动一行并加入。
qcqqc:10m .\nkJjq2@c