簡體   English   中英

如何刪除 Vim 中的每隔一行?

[英]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 幾次。

我們可以使用:normal (或:norm )命令來執行jdd正常模式命令:

:%norm jdd

來源: zzapper 的最佳 Vim 提示頁面。

: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刪除)

  • 范圍 if 從第一行到最后一行( :1,$-1
  • globaly ( 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 )命令來執行jdd正常模式命令:

 :%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.

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