[英]How to merge two multi-line blocks of text in Vim?
我想在 Vim 中合並兩行代碼塊,即,將行k到l並將它們附加到行m到n 。 如果您更喜歡偽代碼解釋: [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,8
和s///
之前的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 '␣'”行為? ”。
要加入線塊,您必須執行以下步驟:
jj
CTRL-v
$
CTRL-END
x
kk$
p
該運動不是最好的(我不是專家),但它可以像您想要的那樣工作。 希望會有一個更短的版本。
這是先決條件,因此此技術效果很好:
abc
和def
的示例中)具有相同的長度XOR這是我的做法(光標在第一行):
qama:5<CR>y$'a$p:5<CR>dd'ajq3@a
你需要知道兩件事:
這是發生了什么:
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.