English 中文(简体)
如何合并 Vim 文本的两个多行区块?
原标题:How to merge two multi-line blocks of text in Vim?
  • 时间:2012-05-25 19:30:08
  •  标签:
  • vim

我想在 Vim 中合并两个行块, 也就是说, 将线条 < em> k 合并到 < em> l < / em > 中, 并通过 < em> < em > 将它们附加到线条上。 如果您喜欢假代码解释 : < code> [line[k+i] + line[m+i] 在范围( min( l-k, n- m)+1)] 中 。

例如,

abc
def
...

123
45
...

应成为

abc123
def45

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

最佳回答

您当然可以使用一个副本/ 粘贴( 使用区块模式选择) 来做所有这一切, 但我猜这不是您想要的 。

如果您想只用 < a href=" http://en.wikipedia.org/wiki/ ex28text_ editor% 29" 来做到这一点, 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 之前的 del 1,4 之前的 //// 指定命令运行的行。

del deletes the given lines. 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 与 a list, using the default delimiter: whitespace. 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 与 two list elements: let l=split(@"," ").

最后,在替换 s/$/=remove(l,0)/ 中,我们将每一行的结尾($ )改为 remove(l,0) remove(l,0) 改变了列表 ,删除并返回其第一个元素。这让我们按照阅读顺序替换被删除的行。我们可以用 remove(l,-1) 取代被删除的行。

问题回答

An elegant and concise Ex command solving the issue can be obtained by combining the :global, :move, and :join commands. 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 this technique, see my answer to an essentially the same question “How to achieve the “paste -d ␣ ” behavior out of the box in Vim?”.

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

  1. Go to the third line: jj
  2. Enter visual block mode: 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
  5. Cut the block: x
  6. Go to the end of the first line: kk$
  7. Paste the block here: p

运动并不是最好的运动(我不是专家 ), 但却是如你所愿的。 但愿它能有更短的版本。

以下是这些要求,所以这种技术运作良好:

  • All lines of the starting block (in the example in the question abc and def) have the same length XOR
  • the first line of the starting block is the longest, and you don t care about the additional spaces in between) XOR
  • The first line of the starting block is not the longest, and you additional spaces to the end.

在这里我如何做( 光标在第一行) :

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

你需要知道两件事:

  • The line number on which the first line of the second group starts (5 in my case), and
  • the number of lines in each group (3 in my example).

这里是怎么回事:

  • qa records everything up to the next q into a "buffer" in a.
  • ma creates a mark on the current line.
  • :5<CR> goes to the next group.
  • y$ yanks the rest of the line.
  • a returns to the mark, set earlier.
  • $p pastes at the end of the line.
  • :5<CR> returns to the second group s first line.
  • dd deletes it.
  • a returns to the mark.
  • jq goes down one line, and stops recording.
  • 3@a repeats the action for each line (3 in my case)

如其他段落所述,街区选择是前进的道路。但您也可以使用以下任何变量:

:!tail -n -6% 糊 -d _ _% - 头 - n 5

此方法依赖于 UNIX 命令行。 创建了 < code> 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.

样本数据与斜坡数据相同。

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

I wouldn t think make it too complicated. I would just set virtualedit on
(:set virtualedit=all)
Select block 123 and all below.
Put it after the first column:

abc    123
def    45
...    ...

并删除从一个空格到一个空格之间的多个空格 :

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

我将使用复杂的重复:)

有鉴于此:

aaa
bbb
ccc

AAA
BBB
CCC

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

qa}jdd  pkJxjq

并按下 (然后您可以使用 ) 所需的倍数 。

最后,你应该与:

aaaAAA
bbbBBB
cccCCC

(加一条新线。 )

解释:

  • qa 开始在 a 中记录复杂重复

  • 跳转到下一个空行

  • jdd 删除下一行

  • 返回上次跳跃前的位置

  • p 粘贴当前线下被删除的行

  • kJ 将当前行附加到上一条的末尾

  • x 删除 J 在合并行之间添加的空间; 如果您想要这个空间, 您可以略去这个空间 。

  • j 转到下一行

  • q 结束复杂的重复记录

之后,您将使用 来运行存储在 a 中的复数重复,然后您就可以使用 来重新运行上次运行的复数重复。

实现这一点的方法有很多种。 我将使用以下两种方法中的任何一个方法合并两块文本。

假设第一个区块位于第1行和第2行,从第10行开始,光标的起始位置为第1行。

( means pressing the enter key.)

1. abc
   def
   ghi        

10. 123
    456
    789

使用命令的宏:复制、粘贴和加入。

qaqqa:+9y pkJjq2@a10G3dd

使用命令在 nth 行编号处移动一行并加入该行的宏。

qcqqc:10m . kJjq2@c

@rampions 回答启发了我,

" paste copied block(already stored in register) to the end of current area
function block_paste(direct)
    let current_line = line( . )
    let copied_contents = split(@", "
")

    for index in range(0, len(copied_contents) - 1)
        if a:direct ==  head  " head
            let res = copied_contents[index] . getline(current_line + index)
        elseif a:direct ==  tail  " tail
            let res = getline(current_line + index) . copied_contents[index]
        else
            let res =   
        endif

        let target_line = current_line + index
        if target_line <= line( $ )
            call setline(target_line, res)
        else
            call append(target_line - 1, res)
        endif
    endfor
endfunction


nnoremap <Leader>bp :call block_paste( tail )<CR>
nnoremap <Leader>bP :call block_paste( head )<CR>

键map bp 可以将复制的块附加到当前块的末端, 键map bP 可以将复制的块插入到当前块的开头

如果您不喜欢 >bp / / bP , 您可以绑定到任何您喜欢的密钥图





相关问题
Autoupdate VIM Plugins?

Is it possible to update vim plugins automatically?

how to unindent in vim without leaving edit mode?

I m writing a lot of python code recently, and i used the tab-to-space mode in vim. I was just wondering how would i unindent in vim without leaving edit mode for example after i finished if...: block....

Scrolling inside Vim in Mac s Terminal

I ve been googling around trying to figure out if it s possible to use my mouse wheel to scroll while inside Vim in Mac s Terminal, with no luck. It seems as if only X11 or iTerm support this. Before ...

Vim - Deleting XML Comments

How do I delete comments in XML? If the opening and the closing comment tags are on the same line, I use :g/^<!--.*-->$/d to delete the comment. How to delete the comments that are spread ...

Limiting a match in vim to certain filetypes?

I have the following in my .vimrc to highlight lines longer than 80 chars: highlight OverLength ctermbg=red ctermfg=white guibg=#592929 match OverLength /\%81v.*/ This works quite well. However, the ...

Profiling Vim startup time

I’ve got a lot of plugins enabled when using Vim – I have collected plugins over the years. I’m a bit fed up with how long Vim takes to start now, so I’d like to profile its startup and see which of ...