[英]How to delete every other line in Vim?
我想從 Vim 緩沖區中刪除每隔一行,從第二個開始,即第 2、4、6 行等。例如,如果緩沖區的內容是:
aaa
bbb
ccc
ddd
eee
fff
然后,在刪除所需的行之后,它應該變成:
aaa
ccc
eee
哪些 Vim 命令可用於自動執行此操作?
完成該任務的一種優雅(且有效)的方法是調用:delete
命令(參見:help :d
)為+
行范圍(與.+1
相同)尋址當前行之后的行(參見:help {address}
),在每一行(參見:help /^
)使用:global
命令(參見:help :g
):
:g/^/+d
您可以為此使用宏。 執行以下操作。
gg
轉到文件的開頭。qq
。dd
。q
。10000@q
PS:要進入命令模式,只需按 Escape 幾次。
:map ^o ddj^o
^o
這里 ^ 代表 CTRL。 遞歸宏每兩行刪除一行。 選擇好你的第一行就完成了。
來自vim 郵件存檔:
:let i=1 | while i <= line('$') | if (i % 2) | exe i . "delete" | endif | let i += 1 | endwhile
(要在 vim 命令行的一行中輸入,將刪除第 1、3、5、7 行,...)
您始終可以通過 shell 命令進行管道傳輸,這意味着您可以使用任何您喜歡的腳本語言:
:%!perl -nle 'print if $. % 2'
(或使用“除非”而不是“如果”,具體取決於您想要的行)
:%!awk -- '++c\%2'
或者
:%!awk -- 'c++\%2'
取決於你想淘汰哪一半。
您可以像這樣使用 Vim 自己的搜索和替換功能:將光標放在第一行,然后在正常模式下輸入:
:.,/fff/s/\n.*\(\n.*\)/\1/g
.,/fff/
是替換的范圍。 它的意思是“從這一行到與正則表達式fff
匹配的行(在本例中為最后一行)。s///
是替代命令。 它查找正則表達式並用字符串替換它的每次出現。 末尾的g
表示只要不斷找到正則表達式就重復替換。\\n.*\\(\\n.*\\)
匹配一個換行符,然后是整行( .*
匹配除換行符之外的任意數量的字符),然后是另一個換行符和另一行。 括號\\(
和\\)
會記錄其中的表達式,因此我們可以稍后使用\\1
使用它。\\1
插入分組的換行符和它后面的行,因為我們不希望下一行也消失 - 我們只希望替換機制通過它,所以我們不會在下一次替換中刪除它。通過這種方式,您可以控制要進行刪除的范圍,而不必使用任何外部工具。
作為另一種方法,如果您的 vim 支持它,您也可以使用 python。
:py import vim; cb = vim.current.buffer; b = cb[:]; cb[:] = b[::2]
b = cb[:]
臨時將當前緩沖區中的所有行復制到b
。 b[::2]
從緩沖區中獲取每一行,並將其分配給整個當前緩沖區cb[:]
。 復制到b
是必要的,因為緩沖區對象似乎不支持擴展切片語法。
這可能不是“vim 方式”,但如果您了解 python,可能會更容易記住。
刪除奇數行 (1, 3, 5, ...):
:%s/\(.*\)\n\(.*\)\n/\2\r/g
刪除偶數行 (2, 4, 6, ...):
:%s/\(.*\)\n.*\n/\1\r/g
搜索文本(形成第一行)后跟一個換行符和一些更多的文本(形成第二行)后跟另一個換行符,並用第一個匹配(奇數行)或第二個匹配(偶數行)替換上面的然后是回車。
你可以在 vim 中試試這個
:1,$-1g/^/+1d
我會盡量說得更清楚(兩部分)
第一部分選擇范圍( :from,to
)
第二部分動作( d
刪除)
:1,$-1
)g
) 刪除 ( +1d
) 下一行您可以嘗試移至文件的第一行並執行:+1d
您將看到下一行消失
我知道它是泥濘的,但它是 vim 並且它有效
調用 sed:
:% !sed -e '2~2 d'
^^^^ pipe file through a shell command
^^^^^^ the command is sed, and -e describes an expression as parameter
^^^^^ starting with the second line, delete every second line
https://stackoverflow.com/a/8334936/16603562
我們可以使用
:normal
(或:norm
)命令來執行j
和dd
正常模式命令::%norm jdd
資料來源: zzapper 提供的 Vim 提示頁面的精華。
這個答案沒有得到足夠的關注,可能是因為這里和鏈接的、凌亂的備忘單上都沒有解釋。 norm 命令運行與它后面的字母等效的正常模式命令。 所以這里運行 j 向下移動一行, dd 刪除它。 在這種情況下,通過添加更多的 'j',這可以推廣到第 X 行。 – @imoatama 2014 年 5 月 13 日
這不起作用(嘗試一下),但是您可以通過添加更多dd
s(或2dd
,將 2 替換為 X-1)來刪除除第 X 行之外的所有內容。或者使用g
的最佳答案, :g/^/+d2
(再次將 2 替換為 X-1。)或者只使用宏或 sed,這也可以實現刪除 X>2 的每 X 行的原始目標。
正如@Lambat 所說,
% 是 1,$ 的簡寫(從第 1 行到最后執行以下命令)– Lambart 2014 年 7 月 29 日
So if you do %norm jjdd
, it will start the counter at line 1, then go to line 3 and delete it, but then it will go to line 2 and then go to line 4 and delete it, etc. This results deleting every奇數行除了第一行,不是每隔三行。
如果您想刪除奇數行,我對為什么 %norm ddj 不起作用感興趣。 ——@Cyker 2018 年 8 月 19 日
這令人困惑。 根據大量測試,我的猜測是原始%norm jdd
有效,因為當命令中的某些內容發生故障時,它會停止:如果您在最后並且執行jdd
,它會執行j
然后停止,因為它不能 go 結束。 但是,如果您執行ddj
,它將首先刪除並停止。 但這不會停止%norm
,它只會停止%norm
內的每一行。
此外,計數器從 1 變為原始行號,它不會更新它。 (這是有道理的,因為如果它更新,您可以執行:%norm p
和無限循環。)如果計數器超過當前文件的最后一行,它會轉到最后一行。 所以它刪除了所有的行。
因此,要刪除每個奇數行而不是偶數行,您可以執行%norm jkddj
。 如果它在末尾,它什么也不做,因為j
在開頭,但如果不是,它刪除當前行號。 但是更容易在運行命令之前刪除第一行: dd ,或者在前面添加 d ( :d|%norm jdd
)。 它的字符數相同,但更直觀。
(順便說一句,這是在 Neovim 上測試的,它可能與 Vim 相同,但我沒有嘗試過)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.