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

31moq8wy  于 2022-11-11  发布在  其他
关注(0)|答案(9)|浏览(314)

我想合并Vim中的两个代码块,也就是说,把 kl 行附加到 mn 行。如果你喜欢伪代码解释的话:[line[k+i] + line[m+i] for i in range(min(l-k, n-m)+1)] .
例如,

abc
def
...

123
45
...

应变成

abc123
def45

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

6kkfgxo0

6kkfgxo01#

您当然可以通过一次复制/粘贴(使用块模式选择)来完成所有这些操作,但我猜这不是您想要的。
如果只想使用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命令接受一系列行作为前缀参数-在上面的例子中,del之前的5,8s///之前的1,4指定了命令在哪些行上操作。
del删除给定的行。它可以接受一个寄存器参数,但如果没有给定,它会将行转储到未命名的寄存器@"中,就像在正常模式下删除一样。然后let l=split(@")使用默认分隔符将删除的行拆分成一个列表:要正确处理已删除行中包含空格的输入,请执行以下操作:

more than 
hour 
our 
never 
ever
after
work is
over
~

我们需要指定一个不同的分隔符,以防止“workis”被拆分为两个列表元素:let l=split(@","\n") .
最后,在替换s/$/\=remove(l,0)/中,我们替换每行的末尾($)与表达式remove(l,0)的值进行比较。remove(l,0)更改列表l,删除并返回它的第一个元素。这样我们就可以按照读取的顺序替换被删除的行。我们可以使用remove(l,-1)以相反的顺序替换删除的行。

vlf7wbxs

vlf7wbxs2#

通过组合:global:move:join命令,可以得到一个优雅简洁的Ex命令来解决该问题。假设第一个行块从缓冲区的第一行开始,并且光标位于第二个块的第一行的前一行,则该命令如下所示。

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

有关此技术的详细说明,请参阅my answer到一个本质上相同的问题“How to achieve the “paste -d '␣'” behavior out of the box in Vim?“。

cpjpxq1n

cpjpxq1n3#

要连接线块,必须执行以下步骤:
1.转到第三行:jj
1.进入视觉封锁模式:CTRL-v
1.将光标锚到行的末尾(对于不同长度的行很重要):$
1.转到结尾:CTRL-END
1.切割块:x
1.转到第一行的末尾:kk$
1.在此处粘贴块:p
这个动作不是最好的(我不是Maven),但是它的效果和你想要的一样。希望有一个更短的版本。
以下是此技术正常工作的先决条件:

  • 起始块的所有行(在问题abcdef的示例中)都具有相同的长度XOR
  • 起始块的第一行是最长的,并且您不关心中间的额外空格)XOR
  • 起始块的第一行不是最长的,并且您在结尾处添加了额外的空格。
huwehgph

huwehgph4#

下面是我的做法(光标在第一行):

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

你需要知道两件事:

  • 第二组的第一行开始的行号(在本例中为5),以及
  • 每组中的行数(在我的示例中为3)。

事情是这样的:

  • qa将直到下一个q的所有内容记录到a中的“缓冲区”中。
  • ma在当前行上创建一个标记。
  • :5<CR>转到下一组。
  • y$会拉动缐条的其他部分。
  • 'a返回到先前设置的标记。
  • $p将粘贴到行尾。
  • :5<CR>返回到第二个组的第一行。
  • dd会删除它。
  • 'a返回标记。
  • jq向下移动一行,并停止记录。
  • 3@a对每一行重复该操作(在我的例子中是3行)
vfhzx4xs

vfhzx4xs5#

正如在其他地方提到的,块选择是一种可行的方法。但是,您也可以使用以下方法的任何变体:
:!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.
qcuzuvrc

qcuzuvrc6#

样本数据与兰皮恩的相同。

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

57hvy0tb7#

我不想把它弄得太复杂。我只想打开virtualedit
:set virtualedit=all
选择块123及以下所有块。
将其放在第一列之后:

abc    123
def    45
...    ...

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

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

zvms9eto8#

我会使用复杂的重复:)
鉴于此:

aaa
bbb
ccc

AAA
BBB
CCC

将光标放在第一行上,按以下键:

qa}jdd''pkJxjq

然后根据需要多次按@a(您可以随后使用@@)。
您最终应该得到:

aaaAAA
bbbBBB
cccCCC

(Plus换行。)
说明:

  • qa开始在a中记录复杂重复
  • }跳到下一个空行
  • jdd删除下一行
  • ''返回到最后一次跳转之前的位置
  • p将删除的行粘贴到当前行下
  • kJ将当前行附加到前一行的末尾
  • x删除J在合并行之间添加的空格;如果您希望空间
  • j转到下一行
  • q结束复杂的重复记录

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

hujrc8aj

hujrc8aj9#

可以有很多方法来完成这一点。我将使用以下两种方法中的任何一种来合并两个文本块。
假设第一块在第1行,第二块从第10行开始,光标的初始位置在第1行。
(\n表示按Enter键。)

1. abc
   def
   ghi        

10. 123
    456
    789

使用以下命令创建宏:复制、粘贴和连接。
qaqqa:+9年
使用宏,使用命令移动第n行号处的行并加入。
qcqqc:10分钟。

相关问题