Visual Studio regex to remove all comments and blank lines in VB.NET code using a macro

后端 未结 3 1572
长情又很酷
长情又很酷 2021-01-14 00:57

I was trying to remove all comments and empty lines in a file with the help of a macro. Now I came up with this solution which deletes the comments(there is some bug descri

相关标签:
3条回答
  • 2021-01-14 01:04

    I've just checked with the two examples from above, '+{.+}$ should do. Optionally, you could go with ('|'')+{.+}$ but the first solution also replaces the xml-descriptions ).

    ''' <summary>
    ''' Method Description
    ''' </summary>
    ''' <remarks></remarks>
    Sub Main()
        ''first comment
        Dim a As String = "" 'second comment
    End Sub
    

    Edit: if you use ('+{.+}$|^$\n) it deletes a) all comments and b) all empty lines. However, if you have a comment and a End Sub/Function following, it takes it up one line which results in a compiler error.

    Before

        ''' <summary>
        ''' 
        ''' </summary>
        ''' <remarks></remarks>
        Sub Main()
            ''first comment
            Dim a As String = "" 'second comment
    
        End Sub
    
        ''' <summary>
        ''' 
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function asdf() As String
            Return "" ' returns nothing
    
        End Function
    

    After

    Sub Main()
        Dim a As String = ""
    End Sub
    
    Public Function asdf() As String
        Return ""         
    End Function
    

    Edit: To delete any empty lines Search Replace the following regex ^$\n with empty.

    0 讨论(0)
  • 2021-01-14 01:15

    To get rid of a line that contains whitespace or nothing, you can use this regex:

    (?m)^[ \t]*[\r\n]+
    

    Your regex, ^[\s|\t]*$\n would work if you specified Multiline mode ((?m)), but it's still incorrect. For one thing, the | matches a literal |; there's no need to specify "or" in a character class. For another, \s matches any whitespace character, including TAB (\t), carriage-return (\r), and linefeed (\n), making it needlessly redundant and inefficient. For example, at the first blank line (after the end of the first Sub), the ^[\s|\t]* will initially try to match everything before the word Public, then it will back off to the end of the previous line, where the $\n can match.

    But a blank line, in addition to being empty or containing only horizontal whitespace (spaces or TABs), may also contain a comment. I choose to treat these "comment-only" lines as blank lines because it's relatively easy to do, and it simplifies the task of matching comments in non-blank lines, which is much harder. Here's my regex:

    ^[ \t]*(?:(?:REM|')[^\r\n]*)?[\r\n]+
    

    After consuming any leading horizontal whitespace, if I see a REM or ' signifying a comment, I consume that and everything after it until the next line separator. Notice that the only thing that's required to be present is the line separator itself. Also notice the absence of the end anchor, $. It's never necessary to use that when you're explicitly matching the line separators, and in this case it would break the regex. In Multiline mode, $ matches only before a linefeed (\n), not before a carriage-return (\r). (This behavior of the .NET flavor is incorrect and rather surprising, given Microsoft's longstanding preference for \r\n as a line separator.)

    Matching the remaining comments is a fundamentally different task. As you've discovered, simply searching for REM or ' is no good because you might find it in a string literal, where it does not signify the start of a comment. What you have to do is start from the beginning of the line, consuming and capturing anything that's not the beginning of a comment or a string literal. If you find a double-quote, go ahead and consume the string literal. If you find a REM or ', stop capturing and go ahead and consume the rest of the line. Then you replace the whole line with just the captured portion--i.e., everything before the comment. Here's the regex:

    (?mn)^(?<line>[^\r\n"R']*(("[^"]*"|(?!REM)R)[^\r\n"R']*)*)(REM|')[^\r\n]*
    

    Or, more readably:

    (?mn)             # Multiline and ExplicitCapture modes
    ^                 # beginning of line
    (?<line>          # capture in group "line"
      [^\r\n"R']*     # any number of "safe" characters
      (
        (
          "[^"]*"     # a string literal
          |
          (?!REM)R    # 'R' if it's not the beginning of 'REM'
        )
        [^\r\n"R']*   # more "safe" characters
      )*
    )                 # stop capturing
    (?:REM|')         # a comment sigil
    [^\r\n]*          # consume the rest of the line
    

    The replacement string would be "${line}". Some other notes:

    • Notice that this regex does not end with [\r\n]+ to consume the line separator, like the "blank lines" regex does.
    • It doesn't end with $ either, for the same reason as before. The [^\r\n]* will greedily consume everything before the line separator, so the anchor isn't needed.
    • The only thing that's required to be present is the REM or '; we don't bother matching any line that doesn't contain a comment.
    • ExplicitCapture mode means I can use (...) instead of (?:...) for all the groups I don't want to capture, but the named group, (?<line>...), still works.
    • Gnarly as it is, this regex would be a lot worse if VB supported multiline comments, or if its string literals supported backslash escapes.

    I don't do VB, but here's a demo in C#.

    0 讨论(0)
  • 2021-01-14 01:27

    Delete the comments first using this regex

    '+\s*(\W|\w).+

    '+ - one or more ' for the beginning of each comment.

    \s* - if there are spaces after the comment.

    (\W|\w).+ - anything that follows except for line terminators.

    Then remove the blank lines left using the regex Mr. Alan Moore provided.

    0 讨论(0)
提交回复
热议问题