从文件的所有行中删除尾随空格的最简单方法是什么?


139

在编程或打开文本文件时遇到在行尾带有空格的文件时,这很常见。通过在trail选项中设置listchars选项然后打开list,vim可以显示此信息。

但是,在整个文件中全局消除尾随空格的最简单方法是什么(理想情况下没有插件)?



这是有关该主题的文档条目
Filipp W.

如果您已安装vim-faq,则可以在那里找到离线答案::h vim-faq并搜索/trailing。难记的标签是:h faq-12.1
Hotschke

Answers:


72

使用键盘绑定去除所有尾随空格

由于我编辑的某些页面实际上需要尾随空格(例如markdown),而其他页面则不需要,因此我设置了一个键绑定,F5以便无需自动即可轻松完成。为此,将以下代码(来自vim.wikia)添加到您的代码.vimrc

"Remove all trailing whitespace by pressing F5
nnoremap <F5> :let _s=@/<Bar>:%s/\s\+$//e<Bar>:let @/=_s<Bar><CR>
  • nnoremap <F5>F5在正常模式下对密钥进行 非递归映射
  • :let _s=@/将最后一个搜索词(来自宏@/)存储在变量中_s
  • <Bar>用作|分隔命令的管道符号的功能,但是|会在此上下文中结束命令,因此<Bar>必须代替使用。
  • :%s/\s\+$//e搜索尾随空格并将其删除到缓冲区中的所有位置(有关此表达式的详细分类,请参阅CarpetSmoker的答案
  • let @/=_s将您的最后一个搜索词恢复到宏@/,以便下次单击时可用n
  • <CR> 结束映射

...或者更具选择性

如果您不想去除所有尾随空白,可以使用一种模式来提高选择性。例如,以下代码显示了仅当分号位于分号后(此处与绑定F8)时,才如何剥离尾部空白。

nnoremap <F8> :let _s=@/<Bar>:%s/;\s\+$/;/e<Bar>:let @/=_s<Bar><CR>

如果像我一样,如果您有一些带有markdown之类的文件,例如heredocs,并且这些文件散布在以分号结尾的编程语句中,则这很有用。


6
尝试:keeppatterns防止覆盖@/。还要看看:keepjumps
布尔2015年

@Bohr您正在使用什么版本的vim?我尝试了:help keeppattern,什么也没得到。
Christopher Bottoms 2015年

@ChristopherBottoms至少是7.4.155版。
波尔

@玻尔。谢谢!来发现我仍在使用7.4.0。我安装了最新版本,并且可用。
Christopher Bottoms 2015年

2
您可以通过将此命令包装在函数中来获得相同的效果,因为此后将自动恢复最后一个搜索词:-)这样,您就不必再费神气了:nohl,如果您要突出显示某个内容,它将继续突出显示它(请参阅我更新的答案)。
Martin Tournoij 2015年

175

“最简单”的方法是只使用:substitute

:%s/\s\+$//e
  • :%s在整个缓冲区:substitute范围内运行%
  • \s t匹配所有空白字符。
  • \+ 重复一次或多次。
  • $ 锚定在该行的末尾。
  • e如果没有匹配项(即文件已经没有尾随空格),则不发出错误的标志。

但是,这可能不是“最佳”方法,因为它会引起两个副作用:

  1. 它将光标移动到最后一个匹配项;
  2. 它将命令添加到历史记录和搜索历史记录中;
  3. 重置上一个搜索词。

您可以通过将其变为函数来修复这两个项目:

fun! TrimWhitespace()
    let l:save = winsaveview()
    keeppatterns %s/\s\+$//e
    call winrestview(l:save)
endfun

然后像这样使用它:

:call TrimWhitespace()
  1. winsaveview()将保存当前“视图”,其中包括的光标位置,折叠,跳跃,等等。winrestview()在最后将从保存变量恢复此。
  2. :keeppatterns防止\s\+$被添加到搜索历史记录模式。
  3. 上次使用的搜索字词在退出功能后会自动恢复,因此我们无需执行任何其他操作。

由于一直很麻烦键入内容:call,因此可以定义一个命令:

command! TrimWhitespace call TrimWhitespace()

可以在不使用的情况下使用:call

:TrimWitespace

您当然可以将其绑定到密钥:

:noremap <Leader>w :call TrimWhitespace()<CR>

有些人喜欢在将文件写入磁盘之前自动执行此操作,如下所示:

autocmd BufWritePre * :call TrimWhitespace()

我不喜欢它,因为某些格式需要尾随空格(例如Markdown),而在另一些情况下,甚至需要在代码中尾随空格(例如格式化电子邮件并使用--<Space>标记来指示签名的开始) )。


无耻的插入模式:不久前,我写了一个Python脚本来一次清理整个项目的空白。


1
如果您不想创建移至先前位置的功能,则只需​`​在替换完成后按两次即可。这将打开的可能性,以创建这样一个oneliner:%s/\s\+$//e | exe "normal ``"
Neaţu奥维迪乌·加布里埃尔

1
@NeaţuOvidiuGabriel,当然,在执行oneliner之后,双反勾号将无法正常工作。;)
通配符

类似:stackoverflow.com/a/1618401。但是我更喜欢Martin的代码。
约翰cj

11

要删除所有尾随空格(在每行末尾),可以使用以下命令:

:%s/ \+$//

要包含选项卡,请使用\s而不是空格。


在命令行中:

$ ex +'%s/\s\+$//e' -cwq file.c

当前目录中的所有文件(递归使用**/*.*):

$ ex +'bufdo!%s/\s\+$//e' -cxa *.*

Python方式:

:py import vim
:pydo vim.current.buffer[linenr - 1] = vim.current.buffer[linenr - 1].strip()

要么:

:py import vim
:py for i, l in enumerate(vim.current.buffer): vim.current.buffer[i] = l.rstrip()

使用lstrip()用于左带(拖尾),rstrip()用于右带(超前)或strip()从两端除去。


这是有用的函数,它可以删除行尾的多余空白,您可以将其添加到您的.vimrc

" Removes superfluous white space from the end of a line
function! RemoveWhiteSpace()
   :%s/\s*$//g
    :'^
    "`.
endfunction

也有为此的DeleteTrailingWhitespace插件。


突出空白

要仔细检查所有尾随空格是否消失,请使用:

  1. 输入/ $以找到它们。如果有的话,vim会为您突出显示它们。

  2. 使用颜色突出显示它们:

    :highlight ws ctermbg=red guibg=red
    :match ws /\s\+$/
    
  3. 使用可见字符(来源):

    :set encoding=utf-8
    :set listchars=trail:·
    :set list
    

另请参阅:高亮显示多余的空间

要在默认情况下突出显示尾随空白,您可以配置.vimrc如下:

highlight ws ctermbg=red guibg=red
match ws /\s\+$/
autocmd BufWinEnter * match ws / \+$/

默认情况下删除空格

如果要确保在保存时自动删除文件中的所有尾随空白,可以将以下命令添加到您的.vimrc

autocmd BufWritePre *.c,*.php :%s/ \+$//ge

不建议这样做,因为它将从用户保存的每个文件中删除尾随空格(即使可能需要空格)。


也可以看看:


5

克里斯托弗·巴托姆斯(Christopher Bottoms)的回答有些令人惊讶:乔纳森·帕拉迪 Jonathan Palardy)对此写了一篇很好的文章。他在其中编写了一个函数,该函数Preserve(command)在运行任意命令时保留编辑器的状态(主要是光标位置和最后一个搜索模式):

function! Preserve(command)
  " Preparation: save window state
  let l:saved_winview = winsaveview()
  " Run the command:
  execute a:command
  " Clean up: restore previous window position
  call winrestview(l:saved_winview)
endfunction

这具有多用途的优点,例如,您可以通过将其映射到以下位置来使用它来替换所有尾随空格(就像乔纳森所做的那样):

nnoremap <F5> :call Preserve("%s/\\s\\+$//e")<CR>

您也可以将其用于视觉模式映射,以删除视觉选择的行上的尾随空格:

xnoremap <F5> :call Preserve("'<,'>s/\\s\\+$//e")<CR>

而且您可以将其用于其他调用,例如=在保留位置的同时使用格式化整个文档(这次最好使用其他密钥,以免发生冲突):

nnoremap <F6> :call Preserve("normal gg=G")<CR>

总而言之,我发现该Preserve(command)函数是一个不错的工具。


2
离开函数时,应自动保留最后使用的搜索词;因此,@/不需要混为一谈(无论如何,在这种情况下)。
Martin Tournoij 2015年

3
winsaveview()并且winrestview()远远优于。
dash-tom-bang

非常正确!根据您的反馈进行了更新。
亚历克斯(Alex)

0

StripTrailingSpaces函数的另一个版本:

if !exists('*StripTrailingWhitespace')
    function! StripTrailingWhitespace() range
        if !&binary && &filetype != 'diff'
            call Preserve(":" . a:firstline . "," . a:lastline . "s/\\s\\+$//e")
        endif
    endfunction
endif

实际上,此功能有一个错误(此错误):由于“范围”选项,该位置没有保留。如果将其删除,效果很好,但是我正在共享代码以获取帮助。

如您所见,它还使用上面所示的Preserve功能,但方式略有不同。

此处的区别在于,我可以选择一个范围的行或段落,vip然后该范围:'<,'>将自动出现在命令提示符下。

这个想法来自Bez Hermoso的职位

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.