如何在Visual Studio 2008中自动删除尾随空格?


122

是否可以将Visual Studio 2008配置为在保存文件时自动删除每行末尾的空白字符?似乎没有内置选项,因此是否有任何扩展名可用于执行此操作?


1
请注意那些正在使用Visual Studio 2010的读者:如果从Microsoft安装PowerCommands扩展,则可以在保存文件时自动格式化文档(通过“工具/选项”启用此功能)。除其他外,这将消除不必要的尾随空白。
steinar 2012年

Answers:


68

CodeMaid是一个非常流行的Visual Studio扩展,它会与其他有用的清理一起自动完成。

我将其设置为在保存时清理文件,我相信这是默认设置。


1
这是此页面上的最佳解决方案。它易于配置,可以按需或为您自动完成,它与VS很好地集成在一起,还具有许多其他非常有用的功能。很好找到arserbin3。
克里斯·R

在此扩展程序中无法关闭完整的代码格式,因此它与自定义缩进样式不兼容。
aemxdp

@Andriy我不明白你的意思。它遵循您在Visual Studio中设置的任何自定义缩进。在“工具”>“选项”>“文本编辑器”>“ [语言]>选项卡
arserbin3 2013年

@ arserbin3我的意思是,如果您要这样格式化代码(pastebin.com/uJqBQ1u2),您就不走运了,因为在保存时,它将自动重新格式化诸如pastebin.com/761Lzra7之类的代码,具体取决于选项。而且没有选择完全关闭缩进规则。而且,如果没有Codemaid文件,重新格式化将不会自动运行,因此您可以使用这种缩进格式保存文件。
aemxdp 2013年

6
@ arserbin3我认为您错过了Andriy的观点。我正在从事一个巨大的开源项目。我不拥有代码-我正在为代码做贡献。我不能更改项目的缩进准则。我希望VisualStudio在修改某些文件时删除结尾的空格,并且不会与文件中的其他任何内容(选项卡,空格,缩进等)混淆。到目前为止,VisualStudio是我使用过的唯一无法做到这一点 IDE。任何其他半熟的编辑器(更不用说IDE)都可以做到。我无法将CodeMaid配置为某种格式,因为格式会有所不同。
kliteyn

71

使用正则表达式查找/替换

在“查找和替换”对话框中,展开“ 查找选项”,选中“ 使用”,然后选择“ 正则表达式”

查找内容:“ :Zs#$

替换为:“”

单击全部替换

在其他编辑器(普通的正则表达式分析器)中,“ :Zs#$”将是“ \s*$”。


44
在VS2012中,我将使用:[^\S\r\n]+(?=\r?$)
M. Dudley

4
如果使用选项卡,[:Zs\t]#$则是一种有用的适应方法。
dlanod

请问如何将其绑定到“保存文件”事件,以便每次我保存文件时都执行该事件?
David FerenczyRogožan

30

您可以创建一个宏,该宏在保存后执行以为您执行此操作。

将以下内容添加到您的宏的EnvironmentEvents模块中。

Private saved As Boolean = False
Private Sub DocumentEvents_DocumentSaved(ByVal document As EnvDTE.Document) _
                                         Handles DocumentEvents.DocumentSaved
    If Not saved Then
        Try
            DTE.Find.FindReplace(vsFindAction.vsFindActionReplaceAll, _
                                 "\t", _
                                 vsFindOptions.vsFindOptionsRegularExpression, _
                                 "  ", _
                                 vsFindTarget.vsFindTargetCurrentDocument, , , _
                                 vsFindResultsLocation.vsFindResultsNone)

            ' Remove all the trailing whitespaces.
            DTE.Find.FindReplace(vsFindAction.vsFindActionReplaceAll, _
                                 ":Zs+$", _
                                 vsFindOptions.vsFindOptionsRegularExpression, _
                                 String.Empty, _
                                 vsFindTarget.vsFindTargetCurrentDocument, , , _
                                 vsFindResultsLocation.vsFindResultsNone)

            saved = True
            document.Save()
        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.OkOnly, "Trim White Space exception")
        End Try
    Else
        saved = False
    End If
End Sub

我已经使用了一段时间了,没有任何问题。我没有创建宏,而是从ace_guidelines.vsmacros中的宏进行了修改,可以通过快速的Google搜索找到它。


8
请注意,这还将用两个空格替换制表符。
crdx 2011年

您将这些文档事件脚本放在哪里?
xagyg

在保存之前执行此操作是否更好,所以您不会收到恼人的VS提示,提示:“嘿,自上次保存以来,文本已更改。您要重新加载吗?”
jedmao

2
不幸的是,VS 2013中没有更多的宏。
弥敦道(Nathan Baulch)2014年


11

您可以通过以下三个操作轻松完成此操作:

  • Ctrl+ A(选择所有文本)

  • 编辑->高级->删除水平空白

  • 编辑->高级->格式选择

等待几秒钟并完成。

如果出现问题,则可以Ctrl+ Z


1
有一个执行此操作的快捷方式:ctrl + w,然后键入Edit.RemoveHorizo​​ntalWhitespace
Josh

8

从已经给出的所有答案中提取元素,这就是我最终得到的代码。(我主要编写C ++代码,但是很容易根据需要检查不同的文件扩展名。)

感谢所有贡献者!

Private Sub DocumentEvents_DocumentSaved(ByVal document As EnvDTE.Document) _
    Handles DocumentEvents.DocumentSaved
    Dim fileName As String
    Dim result As vsFindResult

    Try
        fileName = document.Name.ToLower()

        If fileName.EndsWith(".cs") _
        Or fileName.EndsWith(".cpp") _
        Or fileName.EndsWith(".c") _
        Or fileName.EndsWith(".h") Then
            ' Remove trailing whitespace
            result = DTE.Find.FindReplace( _
                vsFindAction.vsFindActionReplaceAll, _
                "{:b}+$", _
                vsFindOptions.vsFindOptionsRegularExpression, _
                String.Empty, _
                vsFindTarget.vsFindTargetFiles, _
                document.FullName, _
                "", _
                vsFindResultsLocation.vsFindResultsNone)

            If result = vsFindResult.vsFindResultReplaced Then
                ' Triggers DocumentEvents_DocumentSaved event again
                document.Save()
            End If
        End If
    Catch ex As Exception
        MsgBox(ex.Message, MsgBoxStyle.OkOnly, "Trim White Space exception")
    End Try
End Sub


2

不幸的是,我正在使用不支持宏的VWD 2010 Express。所以,我只是做复制/粘贴到记事本+左上角的菜单Edit> Blank Operations> Trim Trailing Space还有其他的相关业务了。然后复制/粘贴回Visual Studio。

也可以使用NetBeans代替Notepad ++,后者在“源”菜单下具有“删除尾随空格”。


只需用空字符串查找/替换:b + $,就可以在VS的快速版本中做到这一点。
合法化

1

除非这是一个人的项目,否则不要这样做。将本地文件与源代码存储库进行比较很简单,清除空白将更改不需要更改的行。我完全理解;我喜欢将所有空白都统一起来-但这是您为了更清洁的协作而应该放弃的东西。


17
大多数优秀的差异工具会忽略不重要的差异,例如尾随空白。如果您的工具没有通过scootersoftware.com
Jim McKeeth,2009年

19
如果公司/项目中的每个人都这样做,差异将是干净的。您只需要清除所有空白一次。这样,您只有一次提交,只能解决空白问题,将来不会出现空白问题。
ThiefMaster 2010年

确实如此。但是,果蝇是否取决于团队。给每个人的工作增加一个额外的步骤,或者甚至增加一个设置以保持同步,往往会造成不必要的摩擦。如果团队可以改变,或者团队成员可以选择自己的IDE等,那么我建议您只保留空白。没什么大不了的。
凯文·康纳

3
空格和缩进清除的问题在于,它会降低源控制功能(例如注释)的有效性,而Beyond Compare将无法解决此问题。最好是第一次就把它弄对。
jammycakes 2011年

4
@KevinConner 与在项目开始时使用巨大的空白提交来修复错误的空白相比,保持IMO 错误的空白似乎更加困难。然后,任何人的编辑器如果是愚蠢而又破损的,在提交之前检查差异时都将知道。
丹·贝查德

1

我认为,如果Jeff Muir版本仅修剪源代码文件(在我的情况下为C#,但很容易添加更多扩展名),则可能会有所改进。我还添加了一个检查以确保文档窗口可见,因为没有检查的某些情况会向我显示奇怪的错误(例如,LINQ to SQL文件'* .dbml')。

Private Sub DocumentEvents_DocumentSaved(ByVal document As EnvDTE.Document) Handles DocumentEvents.DocumentSaved
    Dim result As vsFindResult
    Try
        If (document.ActiveWindow Is Nothing) Then
            Return
        End If
        If (document.Name.ToLower().EndsWith(".cs")) Then
            document.Activate()
            result = DTE.Find.FindReplace(vsFindAction.vsFindActionReplaceAll, ":Zs+$", vsFindOptions.vsFindOptionsRegularExpression, String.Empty, vsFindTarget.vsFindTargetCurrentDocument, , , vsFindResultsLocation.vsFindResultsNone)
            If result = vsFindResult.vsFindResultReplaced Then
                document.Save()
            End If
        End If
    Catch ex As Exception
        MsgBox(ex.Message & Chr(13) & "Document: " & document.FullName, MsgBoxStyle.OkOnly, "Trim White Space exception")
    End Try
End Sub


0

我想我有这个宏的版本,不会在重构时使VS2010崩溃,并且在保存非文本文件时也不会挂起IDE。试试这个:

Private Sub DocumentEvents_DocumentSaved( _
    ByVal document As EnvDTE.Document) _
    Handles DocumentEvents.DocumentSaved
    ' See if we're saving a text file
    Dim textDocument As EnvDTE.TextDocument = _
        TryCast(document.Object(), EnvDTE.TextDocument)

    If textDocument IsNot Nothing Then
        ' Perform search/replace on the text document directly
        ' Convert tabs to spaces
        Dim convertedTabs = textDocument.ReplacePattern("\t", "    ", _
            vsFindOptions.vsFindOptionsRegularExpression)

        ' Remove trailing whitespace from each line
        Dim removedTrailingWS = textDocument.ReplacePattern(":Zs+$", "", _
            vsFindOptions.vsFindOptionsRegularExpression)

        ' Re-save the document if either replace was successful
        ' (NOTE: Should recurse only once; the searches will fail next time)
        If convertedTabs Or removedTrailingWS Then
            document.Save()
        End If
    End If
End Sub

0

我使用ArtisticStyle(C ++)来执行此操作,并且还重新格式化了我的代码。但是,我必须将此添加为外部工具,并且您需要自己触发它,所以您可能不喜欢它。

但是,我发现我可以用更多自定义方式(例如,多行函数参数)重新格式化代码,以至于我可以付出手动运行代码的代价,这真是太好了。该工具是免费的。


0

基于Dyaus的答案和来自连接报告的正则表达式,这是一个宏,用于处理全部保存,不将制表符替换为空格且不需要静态变量的情况。它可能的缺点?似乎有点慢,可能是由于多次调用FindReplace

Private Sub DocumentEvents_DocumentSaved(ByVal document As EnvDTE.Document) _
                                         Handles DocumentEvents.DocumentSaved
    Try
        ' Remove all the trailing whitespaces.
        If vsFindResult.vsFindResultReplaced = DTE.Find.FindReplace(vsFindAction.vsFindActionReplaceAll, _
                             "{:b}+$", _
                             vsFindOptions.vsFindOptionsRegularExpression, _
                             String.Empty, _
                             vsFindTarget.vsFindTargetFiles, _
                             document.FullName, , _
                             vsFindResultsLocation.vsFindResultsNone) Then
            document.Save()
        End If
    Catch ex As Exception
        MsgBox(ex.Message, MsgBoxStyle.OkOnly, "Trim White Space exception")
    End Try
End Sub

对于尝试在Visual Studio 2012加载项中使用此功能的其他人,我最终使用的正则表达式为[ \t]+(?=\r?$)(如果需要,请不要忘记转义反斜杠)。我经过几次徒劳的尝试来解决此问题,但没有通过转换{:b}+$回车符来进行原始转换


-1

这是如何删除尾随空白的一个很好的例子。根据使用此宏所发现的内容,我需要更改一些内容。首先,宏会自动将制表符转换为空格。这并不总是可取的,并且可能会使喜欢制表符的人(通常基于Linux)使情况变得更糟。无论如何,制表符问题与多余的空格问题并不完全相同。其次,宏假定一次只保存一个文件。如果一次保存多个文件,则不会正确删除空白。原因很简单。当前文档被视为您可以看到的文档。第三,它不会对查找结果进行错误检查。这些结果可以为下一步的操作提供更好的情报。例如,如果没有找到并替换空白,无需再次保存文件。通常,我不喜欢是否需要保存全局标志。它倾向于根据未知状态请求麻烦。我怀疑添加该标志仅仅是为了防止无限循环。

    Private Sub DocumentEvents_DocumentSaved(ByVal document As EnvDTE.Document) _
                                         Handles DocumentEvents.DocumentSaved
    Dim result As vsFindResult
    'Dim nameresult As String

    Try
        document.Activate()

        ' Remove all the trailing whitespaces.
        result = DTE.Find.FindReplace(vsFindAction.vsFindActionReplaceAll, _
                             ":Zs+$", _
                             vsFindOptions.vsFindOptionsRegularExpression, _
                             String.Empty, _
                             vsFindTarget.vsFindTargetCurrentDocument, , , _
                             vsFindResultsLocation.vsFindResultsNone)

        'nameresult = document.Name & " " & Str$(result)

        'MsgBox(nameresult, , "Filename and result")

        If result = vsFindResult.vsFindResultReplaced Then
            'MsgBox("Document Saved", MsgBoxStyle.OkOnly, "Saved Macro")
            document.Save()
        Else
            'MsgBox("Document Not Saved", MsgBoxStyle.OkOnly, "Saved Macro")
        End If

    Catch ex As Exception
        MsgBox(ex.Message, MsgBoxStyle.OkOnly, "Trim White Space exception")
    End Try

End Sub

我添加了调试消息框以帮助查看发生了什么。很清楚,多个文件保存不起作用。如果您想和他们一起玩,请取消注释这些行。

关键区别在于使用document.Activate()将文档强制为前台活动的当前文档。如果结果为4,则表示替换了文本。零表示什么都没发生。您将为每个文件看到两次保存。第一个将取代,第二个将无能为力。如果保存无法写入文件,则可能会出现问题,但希望这种情况不会发生。

在使用原始脚本之前,我还没有意识到脚本在Visual Studio中是如何工作的。它使用Visual Basic作为主界面有点令人惊讶,但是它可以很好地完成所需的工作。


对此的一种更改是支持保存焦点并将焦点恢复到保存开始时具有焦点的窗口。只需在Try(使用currdoc = DTE.ActiveDocument)之后和document.Activate()之前保存活动文档。保存完成后,只需激活原始文档(currdoc.Activate())。当在保存过程中切换焦点时,它看起来有点可笑,但是总比失去对您未看过的代码的聚焦要好。
杰夫·缪尔

-1

一个简单的补充是在保存期间删除回车符。

' Remove all the carriage returns.
result = DTE.Find.FindReplace(vsFindAction.vsFindActionReplaceAll, _
                             "\x000d\x000a", _
                             vsFindOptions.vsFindOptionsRegularExpression, _
                             "\x000a", _
                             vsFindTarget.vsFindTargetCurrentDocument, , , _
                             vsFindResultsLocation.vsFindResultsNone)

这项工作的关键是将\ x000d \ x000a更改为\ x000a。\ x前缀表示Unicode模式。这将自动为Linux系统准备源文件的过程。

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.