Visual Studio регулярное выражение для удаления всех комментариев и пустых строк в коде VB.NET с помощью макроса - PullRequest
4 голосов
/ 01 марта 2012

Я пытался удалить все комментарии и пустые строки в файле с помощью макроса. Теперь я пришел к этому решению, которое удаляет комментарии (есть некоторая ошибка, описанная ниже), но не может удалить пустые строки между ними -

Sub CleanCode()
    Dim regexComment As String = "(REM [\d\D]*?[\r\n])|(?<SL>\'[\d\D]*?[\r\n])"
    Dim regexBlank As String = "^[\s|\t]*$\n"
    Dim replace As String = ""

    Dim selection As EnvDTE.TextSelection = DTE.ActiveDocument.Selection
    Dim editPoint As EnvDTE.EditPoint

    selection.StartOfDocument()
    selection.EndOfDocument(True)

    DTE.UndoContext.Open("Custom regex replace")
    Try
        Dim content As String = selection.Text
        Dim resultComment As String = System.Text.RegularExpressions.Regex.Replace(content, regexComment, replace)
        Dim resultBlank As String = System.Text.RegularExpressions.Regex.Replace(resultComment, regexBlank, replace)
        selection.Delete()
        selection.Collapse()
        Dim ed As EditPoint = selection.TopPoint.CreateEditPoint()
        ed.Insert(resultBlank)
    Catch ex As Exception
        DTE.StatusBar.Text = "Regex Find/Replace could not complete"
    Finally
        DTE.UndoContext.Close()
        DTE.StatusBar.Text = "Regex Find/Replace complete"
    End Try
End Sub

Итак, вот как это должно выглядеть до и после запуска макроса.

до

Public Class Class1
    Public Sub New()
        ''asdasdas
        Dim a As String = "" ''asdasd
        ''' asd ad asd
    End Sub


    Public Sub New(ByVal strg As String)

        Dim a As String = ""

    End Sub


End Class

ПОСЛЕ

Public Class Class1
    Public Sub New()
        Dim a As String = ""
    End Sub
    Public Sub New(ByVal strg As String)
        Dim a As String = ""
    End Sub
End Class

В основном, есть две основные проблемы с макросом

  • Невозможно удалить пустые строки между ними.
  • Если есть фрагмент кода, который выглядит следующим образом

Dim a as String = "Name='Soham'"

Затем, после запуска макроса, он становится

Dim a as String = "Name='"

Ответы [ 3 ]

7 голосов
/ 05 марта 2012

Чтобы избавиться от строки, содержащей пробелы или ничего, вы можете использовать это регулярное выражение:

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

Ваше регулярное выражение ^[\s|\t]*$\n будет работать, если вы указали многострочный режим ((?m)), но оно по-прежнему неверно. С одной стороны, | соответствует буквальному |; нет необходимости указывать «или» в классе символов. С другой стороны, \s соответствует любому символу пробела, включая TAB (\t), возврат каретки (\r) и перевод строки (\n), что делает его ненужным избыточным и неэффективным. Например, в первой пустой строке (после конца первой Sub) ^[\s|\t]* сначала попытается сопоставить все перед словом Public, затем вернется к концу предыдущей строки, где $\n может совпадать.

Но пустая строка, помимо того, что она пустая или содержит только горизонтальные пробелы (пробелы или табуляции), также может содержать комментарий. Я предпочитаю рассматривать эти строки «только для комментариев» как пустые строки, потому что это относительно легко сделать, и это упрощает задачу сопоставления комментариев в непустых строках, что намного сложнее. Вот мое регулярное выражение:

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

После использования любого начального горизонтального пробела, если я вижу REM или ', обозначающий комментарий, я использую это и все после него до разделителя следующей строки. Обратите внимание, что единственное, что требуется для присутствия - это сам разделитель строк. Также обратите внимание на отсутствие концевого якоря, $. Нет необходимости использовать это, когда вы явно сопоставляете разделители строк, и в этом случае это нарушит регулярное выражение. В многострочном режиме $ соответствует только до перевода строки (\n), а не до возврата каретки (\r). (Такое поведение разновидности .NET является неправильным и довольно удивительным, учитывая давнее предпочтение Microsoft для \r\n в качестве разделителя строк.)

Соответствие оставшимся комментариям - принципиально иная задача. Как вы обнаружили, простой поиск REM или ' не годится, потому что вы можете найти его в строковом литерале, где он не означает начало комментария. Вам нужно начать с начала строки, потребляя и захватывая все, что не является началом комментария или строкового литерала. Если вы найдете двойные кавычки, используйте строковый литерал. Если вы обнаружите REM или ', прекратите захват и продолжайте поглощать оставшуюся часть линии. Затем вы заменяете всю строку только захваченной частью, то есть всем перед комментарием. Вот регулярное выражение:

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

Или, более наглядно:

(?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

Строка замены будет "${line}". Некоторые другие заметки:

  • Обратите внимание, что это регулярное выражение не оканчивается на [\r\n]+, чтобы использовать разделитель строк, как регулярное выражение "пустые строки".
  • Также не заканчивается $ по той же причине, что и раньше. [^\r\n]* будет жадно потреблять все до разделителя строк, поэтому привязка не нужна.
  • Единственное, что требуется для присутствия - это REM или '; мы не ищем соответствия ни одной строке, в которой нет комментария.
  • Режим ExplicitCapture означает, что я могу использовать (...) вместо (?:...) для всех групп, которые я не хочу захватывать, но именованная группа, (?<line>...), все еще работает.
  • Как ни крути, это регулярное выражение было бы намного хуже, если бы VB поддерживал многострочные комментарии или если его строковые литералы поддерживали escape-символы обратной косой черты.

Я не делаю VB, но вот демонстрация в C # .

0 голосов
/ 09 марта 2018

Сначала удалите комментарии, используя это регулярное выражение

+ \ S * (\ W | \ ш). +

'+ - один или несколько' в начале каждого комментария.

\ s * - если после комментария есть пробелы.

(\ W | \ w). + - все, что следует за исключением разделителей строки.

Затем удалите оставшиеся пустые строки с помощью регулярного выражения, предоставленного мистером Аланом Муром.

0 голосов
/ 01 марта 2012

Я только что проверил два приведенных выше примера, '+{.+}$ должно подойти. При желании вы можете использовать ('|'')+{.+}$, но первое решение также заменяет xml-описания).

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

Редактировать: если вы используете ('+{.+}$|^$\n), он удаляет а) все комментарии и б) все пустые строки. Однако, если у вас есть комментарий и последующая функция End Sub / Function, она занимает одну строку, что приводит к ошибке компилятора.

До

    ''' <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

После

Sub Main()
    Dim a As String = ""
End Sub

Public Function asdf() As String
    Return ""         
End Function

Редактировать: Удалить все пустые строки. Поиск Заменить следующее регулярное выражение ^$\n пустым.

...