繁体   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