簡體   English   中英

如何在 Vim 中合並兩個多行文本塊?

[英]How to merge two multi-line blocks of text in Vim?

我想在 Vim 中合並兩行代碼塊,即,將行kl並將它們附加到行mn 如果您更喜歡偽代碼解釋: [line[k+i] + line[m+i] for i in range(min(lk, nm)+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 命令接受一系列行作為前綴參數 - 在上述情況下, del之前的5,8s///之前的1,4指定命令操作的行。

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)改變列表l ,刪除並返回它的第一個元素。 這讓我們可以按照閱讀的順序替換已刪除的行。 我們可以使用remove(l,-1)以相反的順序替換已刪除的行。

通過組合:global:move:join命令可以獲得一個優雅而簡潔的 Ex 命令來解決這個問題。 假設第一個行塊從緩沖區的第一行開始,並且光標位於第二個塊的第一行之前的行,命令如下。

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

有關此技術的詳細說明,請參閱對基本相同問題的回答“如何在 Vim 中實現開箱即用的“粘貼 -d '␣'”行為? ”。

要加入線塊,您必須執行以下步驟:

  1. 轉到第三行: jj
  2. 進入可視塊模式: CTRL-v
  3. 將光標定位到行尾(對於不同長度的行很重要): $
  4. 走到最后: CTRL-END
  5. 切塊: x
  6. 轉到第一行的末尾: kk$
  7. 在此處粘貼塊: p

該運動不是最好的(我不是專家),但它可以像您想要的那樣工作。 希望會有一個更短的版本。

這是先決條件,因此此技術效果很好:

  • 起始塊的所有行(在問題abcdef的示例中)具有相同的長度XOR
  • 起始塊的第一行是最長的,你不需要關心中間的額外空格) XOR
  • 起始塊的第一行不是最長的,並且您在末尾添加空格。

這是我的做法(光標在第一行):

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

你需要知道兩件事:

  • 第二組的第一行開始的行號(在我的情況下為 5),以及
  • 每組中的行數(在我的示例中為 3)。

這是發生了什么:

  • qa將直到下一個q的所有內容記錄到 a 中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

我不認為讓它太復雜。 我只想設置 virtualedit
( :set virtualedit=all )
選擇塊 123 及以下所有。
把它放在第一列之后:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM