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

本文翻译自:Merge multiple lines (two blocks) in Vim

I'd like to merge two blocks of lines in Vim, ie take lines n..m and append them to lines a..b . 我想在Vim中合并两行线,即取n..m行并将它们附加到a..b行。 If you prefer a pseudocode explanation: [a[i] + b[i] for i in min(len(a), len(b))] 如果您希望使用伪代码解释: [a[i] + b[i] for i in min(len(a), len(b))]

Example: 例:

abc
def
...

123
45
...

should become 应该成为

abc123
def45

Is there a nice way to do this without doing copy&paste manually? 有没有一种好的方法,而无需手动进行复制和粘贴?


#1楼

参考:https://stackoom.com/question/j9Fe/在Vim中合并多行-两个块


#2楼

To join blocks of line, you have to do the following steps: 要连接线段,您必须执行以下步骤:

  1. Go to the third line: jj 转到第三行: jj
  2. Enter visual block mode: CTRL-v 进入可视块模式: CTRL-v
  3. Anchor the cursor to the end of the line (important for lines of differing length): $ 将光标锚定到行尾(对于长度不同的行很重要): $
  4. Go to the end: CTRL-END 转到最后: CTRL-END
  5. Cut the block: x 切块: x
  6. Go to the end of the first line: kk$ 转到第一行的末尾: kk$
  7. Paste the block here: p 在此处粘贴块: p

The movement is not the best one (I'm not an expert), but it works like you wanted. 这个运动不是最好的运动(我不是专家),但是它的运行就像您想要的那样。 Hope there will be a shorter version of it. 希望会有一个简短的版本。

Here are the prerequisits so this technique works well: 这是必备条件,因此此技术效果很好:

  • All lines of the starting block (in the example in the question abc and def ) have the same length XOR 起始块的所有行(在问题abcdef的示例中)的长度XOR相同
  • the first line of the starting block is the longest, and you don't care about the additional spaces in between) XOR 起始块的第一线是最长的,并且不关心之间的额外空间)XOR
  • The first line of the starting block is not the longest, and you additional spaces to the end. 起始块的第一行不是最长的行,并且您在末尾还有其他空格。

#3楼

You can certainly do all this with a single copy/paste (using block-mode selection), but I'm guessing that's not what you want. 您当然可以通过单个复制/粘贴(使用块模式选择)来完成所有这些操作,但是我想那不是您想要的。

If you want to do this with just Ex commands 如果您只想使用Ex命令来执行此操作

:5,8del | let l=split(@") | 1,4s/$/\=remove(l,0)/

will transform 会转变

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

into 进入

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

UPDATE: An answer with this many upvotes deserves a more thorough explanation. 更新:如此众多的答案应该得到更详尽的解释。

In Vim, you can use the pipe character ( | ) to chain multiple Ex commands, so the above is equivalent to 在Vim中,可以使用竖线字符( | )链接多个Ex命令,因此上述内容等效于

:5,8del
:let l=split(@")
:1,4s/$/\=remove(l,0)/

Many Ex commands accept a range of lines as a prefix argument - in the above case the 5,8 before the del and the 1,4 before the s/// specify which lines the commands operate on. 许多Ex命令接受一系列行作为前缀参数-在上述情况下, del之前的5,8s///之前的1,4指定了命令在哪些行上进行操作。

del deletes the given lines. del删除给定的行。 It can take a register argument, but when one is not given, it dumps the lines to the unnamed register, @" , just like deleting in normal mode does. let l=split(@") then splits the deleted lines into a list, using the default delimiter: whitespace. 它可以使用一个寄存器参数,但是当不给出参数时,它会将行转储到未命名的寄存器@" ,就像在普通模式下删除一样。 let l=split(@")然后将删除的行拆分为一个列表,使用默认的定界符:空格。 To work properly on input that had whitespace in the deleted lines, like: 要在删除的行中包含空格的输入上正常工作,例如:

more than 
hour 
our 
never 
ever
after
work is
over
~

we'd need to specify a different delimiter, to prevent "work is" from being split into two list elements: let l=split(@","\\n") . 我们需要指定一个不同的定界符,以防止将“工作是”拆分为两个列表元素: let l=split(@","\\n")

Finally, in the substitution s/$/\\=remove(l,0)/ , we replace the end of each line ( $ ) with the value of the expression remove(l,0) . 最后,在替换s/$/\\=remove(l,0)/ ,我们用表达式remove(l,0)的值替换每行( $ )的结尾。 remove(l,0) alters the list l , deleting and returning its first element. remove(l,0)更改列表l ,删除并返回其第一个元素。 This lets us replace the deleted lines in the order in which we read them. 这使我们可以按读取顺序替换已删除的行。 We could instead replace the deleted lines in reverse order by using remove(l,-1) . 相反,我们可以使用remove(l,-1)以相反的顺序替换已删除的行。


#4楼

Here's how I'd do it (with the cursor on the first line): 这是我的操作方式(光标放在第一行):

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

You need to know two things: 您需要知道两件事:

  • The line number on which the first line of the second group starts (5 in my case), and 第二组的第一行开始的行号(在我的情况下为5),以及
  • the number of lines in each group (3 in my example). 每组中的行数(在我的示例中为3)。

Here's what's going on: 这是怎么回事:

  • qa records everything up to the next q into a "buffer" in a . qa记录一切到一个新q成一个“缓冲” a
  • ma creates a mark on the current line. ma在当前行上创建一个标记。
  • :5<CR> goes to the next group. :5<CR>转到下一组。
  • y$ yanks the rest of the line. y$删除其余部分。
  • 'a returns to the mark, set earlier. 'a返回到先前设置的标记。
  • $p pastes at the end of the line. $p粘贴在该行的末尾。
  • :5<CR> returns to the second group's first line. :5<CR>返回第二组的第一行。
  • dd deletes it. dd删除它。
  • 'a returns to the mark. 'a返回标记。
  • jq goes down one line, and stops recording. jq下降一行,并停止记录。
  • 3@a repeats the action for each line (3 in my case) 3@a对每一行重复执行该操作(本例中为3)

#5楼

As mentioned elsewhere, block selection is the way to go. 如其他地方所述,块选择是必经之路。 But you can also use any variant of: 但您也可以使用以下任何变体:

:!tail -n -6 % | paste -d '\\0' % - | head -n 5

This method relies on the UNIX command line. 此方法依赖于UNIX命令行。 The paste utility was created to handle this sort of line merging. 创建了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.

#6楼

An elegant and concise Ex command solving the issue can be obtained by combining the :global , :move , and :join commands. 可以通过组合:global:move:join命令来获得一个优雅简洁的Ex命令来解决该问题。 Assuming that the first block of lines starts on the first line of the buffer, and that the cursor is located on the line immediately preceding the first line of the second block, the command is as follows. 假设第一个行块在缓冲区的第一行开始,并且光标位于第二个块的第一行之前的行上,则命令如下。

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

For detailed explanation of the technique used, see the answer I gave to the question " Vim paste -d ' ' behavior out of the box? ". 有关所用技术的详细说明,请参见我对问题“ Vim paste -d''行为开箱即用? ”的回答

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值