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

时间:2011-09-21 07:15:32

标签: vim

有时我会在文件底部留下空行。
如何在保存时修剪它们?

更新

谢谢大家,所有解决方案似乎都有效 不幸的是,它们都重置了当前光标位置,所以我写了这个函数

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

au BufWritePre *.py call TrimEndLines()

6 个答案:

答案 0 :(得分:29)

这个替代命令应该这样做:

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

请注意,这将删除仅包含空格的所有尾随行。要仅删除真正的“空”行,请从上面的命令中删除\s*

修改

说明:

  • \( .....启动一个匹配组
  • $\n ...匹配一个新行(行尾字符后跟回车符。)
  • \s* ...在此新行上允许任意数量的空白
  • \) .....结束比赛组
  • \+ .....允许此群组出现任意数量(一个或多个)。
  • \%$ ...匹配文件末尾

因此,正则表达式匹配仅包含空格的任意数量的相邻行,仅由文件末尾终止。然后,substitute命令将匹配替换为空字符串。

答案 1 :(得分:12)

优雅的解决方案可以基于:vglobal命令(或者,也就是说 同样的事情,:global!修饰符),

:v/\_s*\S/d

此命令在每条没有的行上执行:delete 其中的非空白字符以及在剩余文本中的结尾之后 缓冲区。因此,该命令将删除拖尾空行。

删除空行(严格意义上说,而不是空行) 缓冲区末尾只包含空格,改变模式 :vglobal命令如下。

:v/\n*./d

在包含大块连续空格的巨大稀疏文件上 字符(从大约几百千字节的空白开始)以上 命令可能具有不可接受的性能。如果是这样的话,同样如此 优雅的想法可以用来将:vglobal命令转换成很多 更快的范围删除命令。

对于空白行:

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

对于空行:

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

两个命令的本质是相同的,即删除行 属于:delete指定的范围。范围已定义 根据这三个步骤:

  1. 在解释之前将光标移动到缓冲区的第一行 范围的其余部分(0;,请参阅:help :;)。 0之间的区别 和1行号是前者允许匹配的第一个 line,当稍后在范围内使用搜索模式时。

  2. 搜索描述非拖尾空白的模式的行 行(\_s*\S\n*.)不匹配(否定归因于\@! 原子)。将范围的起始行设置为该行。

  3. 将范围的结束行设置为缓冲区的最后一行。

  4. 要在保存时运行上述命令之一,请使用auto-command触发它 BufWrite事件(或其同义词,BufWritePre)。

答案 2 :(得分:8)

你可以将它放入你的vimrc

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

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

详情:

  • BufWritePre是将缓冲区写入文件之前的事件。
  • $put _在文件末尾添加一个空行(来自始终为空的寄存器)
  • |链出口命令
  • $;?\(^\s*$\)\@!?转到文件末尾($),然后(;)向后查找(?…?)第一行并非完全空白({{ 1}}),在vim搜索中也看到\(^\s*$\)\@!的负面断言。
  • :help /\@!形成从行×××+ 1到最后一行
  • 的范围
  • ×××+1,$删除行范围。

答案 3 :(得分:1)

受@Prince Goulash解决方案的启发,将以下内容添加到~/.vimrc以删除Ruby和Python文件的每次保存的尾随空白行:

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

答案 4 :(得分:0)

我在使用替换时发现以前的答案在操作非常大的文件时遇到了麻烦并污染了我的寄存器。这是我提出的一个功能,它对我来说效果更好,并避免污染寄存器:

" 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()

答案 5 :(得分:0)

我有一个名为 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()