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

时间:2012-05-25 19:30:08

标签: vim

我想在Vim中合并两个线块,即取n..m行并将它们附加到行a..b。如果您更喜欢伪代码说明:[a[i] + b[i] for i in min(len(a), len(b))]

示例:

abc
def
...

123
45
...

应该成为

abc123
def45

如果不手动复制和粘贴,有没有很好的方法呢?

9 个答案:

答案 0 :(得分:881)

你当然可以通过一次复制/粘贴(使用块模式选择)完成所有这些,但我猜这不是你想要的。

如果您只想使用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之前的del1,4之前的s///指定了哪些行命令操作。

del删除给定的行。它可以采用寄存器参数,但是如果没有给出,它会将行转储到未命名的寄存器@",就像在正常模式下删除一样。 let l=split(@")然后使用默认分隔符:空格将已删除的行拆分为列表。要在已删除行中包含空格的输入上正常工作,例如:

more than 
hour 
our 
never 
ever
after
work is
over
~

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

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

答案 1 :(得分:55)

可以通过以下方式获得解决问题的优雅简洁的Ex命令 结合:global:move:join命令。假设那个 第一个行块在缓冲区的第一行开始,而那个 光标位于紧靠第一行之前的行上 第二个块,命令如下。

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

有关所用技术的详细说明,请参阅我给的answer 问题“Vim paste -d ' ' behavior out of the box?”。

答案 2 :(得分:44)

要加入行块,您必须执行以下步骤:

  1. 转到第三行:jj
  2. 进入视觉区块模式:CTRL-v
  3. 将光标锚定到行尾(对于不同长度的行很重要):$
  4. 转到最后:CTRL-END
  5. 剪切块:x
  6. 转到第一行的末尾:kk$
  7. 将块粘贴到此处:p
  8. 运动不是最好的运动(我不是专家),但它的运作方式与你想要的一样。希望会有更短的版本。

    以下是先决条件,因此这项技术运作良好:

    • 起始块的所有行(在问题abcdef中的示例中)具有相同的长度 XOR
    • 起跑线的第一行是最长的,你不在乎其间的额外空格。 XOR
    • 起始块的第一行不是最长的,你可以在末尾添加额外的空格。

答案 3 :(得分:19)

这是我如何做到的(光标在第一行):

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

你需要知道两件事:

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

这是发生了什么:

  • qaq中的所有内容记录到a中的“缓冲区”中。
  • ma在当前行上创建标记。
  • :5<CR>转到下一组。
  • y$猛拉其余部分。
  • 'a返回前面设置的标记。
  • $p贴在行尾。
  • :5<CR>返回第二组的第一行。
  • dd删除它。
  • 'a返回商标。
  • jq下线一行,然后停止录音。
  • 3@a重复每一行的动作(在我的情况下为3)

答案 4 :(得分:8)

如其他地方所述,块选择是要走的路。但您也可以使用以下任何变体:

:!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.

答案 5 :(得分:3)

样本数据与rampion的相同。

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

答案 6 :(得分:3)

我不认为让它变得太复杂。 我只想在上面设置virtualedit (:set virtualedit=all
选择块123以及下面的全部 把它放在第一栏之后:

abc    123
def    45
...    ...

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

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

答案 7 :(得分:2)

我会使用复杂的重复:)

鉴于此:

aaa
bbb
ccc

AAA
BBB
CCC

将光标放在第一行的第一个“a”处,按以下键:

qq}jdd''$pkJj0q

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

你最终应该:

aaaAAA
bbbBBB
cccCCC

(加上换行符。)

答案 8 :(得分:1)

可以通过多种方式实现这一目标。我将使用以下两种方法中的任何一种合并两个文本块。

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

(\ n表示按回车键。)

1. abc
   def
   ghi        

10. 123
    456
    789

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

  

qaqqa:+ 9Y \ npkJjq2 @ a10G3dd

使用命令使用宏

在第n个行号处移动一行并加入。

  

qcqqc:10m。\ nkJjq2 @ c