簡體   English   中英

如何在 Vim 中修剪文件末尾的空行?

[英]How can I trim blank lines at the end of file in Vim?

有時我不小心在我正在編輯的文件末尾留下空行。
如何在 Vim 中保存時修剪它們?

更新

謝謝大家,所有解決方案似乎都有效。
不幸的是,它們都重置了當前光標位置,因此我編寫了以下函數。

function TrimEndLines()
    let save_cursor = getpos(".")
    silent! %s#\($\n\s*\)\+\%$##
    call setpos('.', save_cursor)
endfunction

autocmd BufWritePre *.py call TrimEndLines()

這個替代命令應該這樣做:

:%s#\($\n\s*\)\+\%$##

請注意,這會刪除所有僅包含空格的尾隨行。 要僅刪除真正的“空”行,請從上述命令中刪除\\s*

編輯

解釋:

  • \\( ..... 開始比賽組
  • $\\n ... 匹配新行(行尾字符后跟回車符)。
  • \\s* ... 在這個新行上允許任意數量的空格
  • \\) ..... 結束比賽組
  • \\+ ..... 允許該組出現任意次數(一次或多次)。
  • \\%$ ... 匹配文件末尾

因此,正則表達式匹配任意數量的僅包含空格的相鄰行,僅在文件末尾終止。 然后替換命令用空字符串替換匹配項。

1.一個優雅的解決方案可以基於:vglobal命令(或者,這是同一件事,基於:global!修飾符):

:v/\_s*\S/d

此命令在其中沒有非空白字符的每一行上執行:delete ,以及在它之后的剩余文本中到緩沖區末尾(參見:help /\\s:help /\\S:help /\\_來理解模式)。 因此,該命令會刪除尾部的空白行。

要刪除嚴格意義上的行——而不是只包含空格的空白行——更改:vglobal命令中的模式,如下所示。

:v/\n*./d

2.在包含大塊連續空白字符(從大約數百千字節的空白開始)的巨大稀疏文件上,上述命令可能具有不可接受的性能。 如果是這種情況,可以使用相同的優雅想法將:vglobal命令轉換為更快(但可能不那么優雅)的:delete命令,具有模式定義的范圍。

對於空行:

:0;/^\%(\_s*\S\)\@!/,$d

對於空行:

:0;/^\%(\n*.\)\@!/,$d

兩個命令的本質是一樣的; 即刪除屬於指定范圍的行,這些行是根據以下三個步驟定義的:

  1. 將光標移動到緩沖區的第一行,然后再解釋范圍的其余部分 ( 0; --see :help :; )。 01行號之間的區別在於前者允許在第一行匹配,當存在用於定義范圍結束行的搜索模式時。

  2. 搜索描述非尾隨空行( \\_s*\\S\\n*. )的模式不匹配的行(否定是由於\\@!原子 - 請參閱:help /\\@! )。 將范圍的起始行設置為該行。

  3. 將范圍的結束行設置為緩沖區的最后一行 ( ,$ —see :help :$ )。

3.要在保存時運行上述任何命令,請使用將在BufWrite事件(或其同義詞BufWritePre )上觸發的自動命令觸發它。

你可以把它放到你的 vimrc 中

au BufWritePre *.txt $put _ | $;?\(^\s*$\)\@!?+1,$d

(用你想要的任何通配符模式替換*.txt

細節:

  • BufWritePre是將緩沖區寫入文件之前的事件。
  • $put _在文件末尾附加一個空行(來自始終為空的寄存器)
  • | 連鎖 Ex 命令
  • $;?\\(^\\s*$\\)\\@!? 轉到文件末尾 ( $ ) 然后 ( ; ) 向后查找 ( ?…? ) 第一行不是完全空白的 ( \\(^\\s*$\\)\\@! ),另見:help /\\@! 用於 vim 搜索中的否定斷言。
  • ×××+1,$形成從行×××+1 到最后一行的范圍
  • d刪除行范圍。

受到@Prince Goulash 解決方案的啟發,將以下內容添加到您的~/.vimrc以刪除每次保存 Ruby 和 Python 文件時的尾隨空行:

autocmd FileType ruby,python autocmd BufWritePre <buffer> :%s/\($\n\s*\)\+\%$//e

我發現以前使用替代的答案在處理非常大的文件時會引起麻煩並污染我的寄存器。 這是我想出的一個函數,它對我來說表現更好,並且可以避免污染寄存器:

" Strip trailing empty newlines
function TrimTrailingLines()
  let lastLine = line('$')
  let lastNonblankLine = prevnonblank(lastLine)
  if lastLine > 0 && lastNonblankLine != lastLine
    silent! execute lastNonblankLine + 1 . ',$delete _'
  endif
endfunction

autocmd BufWritePre <buffer> call TrimTrailingLines()

我有一個名為Preserve的獨立函數,我可以從其他函數調用它,使用 Preserve 做其他事情很容易:

" remove consecutive blank lines
" see Preserve function definition
" another way to remove blank lines :g/^$/,/./-j
" Reference: https://stackoverflow.com/a/7496112/2571881
if !exists('*DelBlankLines')
    fun! DelBlankLines() range
        if !&binary && &filetype != 'diff'
            call Preserve(':%s/\s\+$//e')
            call Preserve(':%s/^\n\{2,}/\r/ge')
            call Preserve(':%s/\v($\n\s*)+%$/\r/e')
        endif
    endfun
endif

就我而言,我在文件末尾至少保留一個空行,但不超過一個。

" Utility function that save last search and cursor position
" http://technotales.wordpress.com/2010/03/31/preserve-a-vim-function-that-keeps-your-state/
" video from vimcasts.org: http://vimcasts.org/episodes/tidying-whitespace
" using 'execute' command doesn't overwrite the last search pattern, so I
" don't need to store and restore it.
" preserve function
if !exists('*Preserve')
    function! Preserve(command)
        try
            let l:win_view = winsaveview()
            "silent! keepjumps keeppatterns execute a:command
            silent! execute 'keeppatterns keepjumps ' . a:command
        finally
            call winrestview(l:win_view)
        endtry
    endfunction
endif

這就是為什么我有一個單獨的 Preserve 功能:

command! -nargs=0 Reindent :call Preserve('exec "normal! gg=G"')

" join lines keeping cursor position
nnoremap J :call Preserve(':join')<CR>
nnoremap <Leader>J :call Preserve(':join!')<CR>

" Reloads vimrc after saving but keep cursor position
if !exists('*ReloadVimrcFunction')
    function! ReloadVimrcFunction()
        call Preserve(':source $MYVIMRC')
        " hi Normal guibg=NONE ctermbg=NONE
        windo redraw
        echom "Reloaded init.vim"
    endfunction
endif
noremap <silent> <Leader>v :drop $MYVIMRC<cr>
command! -nargs=0 ReloadVimrc :call ReloadVimrcFunction()

" Strip trailing whitespaces
command! Cls :call Preserve(':%s/\v\s+$//e')

如果你想創建一個自動命令,你必須創建一個組以避免自動命令過載:

augroup removetrailingspaces
    au!
    au! BufwritePre *.md,*.py,*.sh,*.zsh,*.txt :call Preserve(':%s/\v\s+$//e')
augroup END

這個是改文件頭(如果有什么建議)隨意交互:

" trying avoid searching history in this function
if !exists('*ChangeHeader')
    fun! ChangeHeader() abort
        if line('$')>=7
            call Preserve(':1,7s/\v(Last (Change|Modified)|date):\s+\zs.*/\=strftime("%b %d, %Y - %H:%M")/ei')
        endif
    endfun
endif

" dos2unix ^M
if !exists('*Dos2unixFunction')
    fun! Dos2unixFunction() abort
        "call Preserve('%s/ $//ge')
        call Preserve(":%s/\x0D$//e")
        set ff=unix
        set bomb
        set encoding=utf-8
        set fileencoding=utf-8
    endfun
endif
com! Dos2Unix :call Dos2unixFunction()

暫無
暫無

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

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