Regex, чтобы убрать комментарии строки из C # - PullRequest
40 голосов
/ 19 августа 2010

Я работаю над подпрограммой для удаления комментариев из блоков или из некоторого кода C #. Я просмотрел другие примеры на сайте, но не нашел точного ответа, который я ищу.

Я могу сопоставить блочные комментарии (/ * comment * /) полностью, используя это регулярное выражение с RegexOptions.Singleline:

(/\*[\w\W]*\*/)

И я могу сопоставить строковые комментарии (// comment) полностью, используя это регулярное выражение с RegexOptions.Multiline:

(//((?!\*/).)*)(?!\*/)[^\r\n]

Примечание: я использую [^\r\n] вместо $, потому что $ также включает в себя \r в матче.

Однако, это не вполне работает так, как я хочу.

Вот мой тестовый код, с которым я сопоставляю:

// remove whole line comments
bool broken = false; // remove partial line comments
if (broken == true)
{
    return "BROKEN";
}
/* remove block comments
else
{
    return "FIXED";
} // do not remove nested comments */ bool working = !broken;
return "NO COMMENT";

Соответствует выражению блока

/* remove block comments
else
{
    return "FIXED";
} // do not remove nested comments */

это хорошо и хорошо, но выражение строки соответствует

// remove whole line comments
// remove partial line comments

и

// do not remove nested comments

Кроме того, если у меня нет выражения * / positive в выражении строки дважды, это соответствует

// do not remove nested comments *

что я действительно не хочу.

Мне нужно выражение, которое будет сопоставлять символы, начиная с //, до конца строки, но не содержит */ между // и концом строки.

Кроме того, просто чтобы удовлетворить мое любопытство, кто-нибудь может объяснить, почему мне нужно смотреть вдаль дважды? (//((?!\*/).)*)[^\r\n] и (//(.)*)(?!\*/)[^\r\n] будут включать *, но (//((?!\*/).)*)(?!\*/)[^\r\n] и (//((?!\*/).)*(?!\*/))[^\r\n] не будут.

Ответы [ 6 ]

80 голосов
/ 19 августа 2010

В обоих ваших регулярных выражениях (для блочных и строчных комментариев) есть ошибки.Если хотите, я могу описать ошибки, но я чувствую, что, возможно, будет более продуктивно, если я напишу новые, особенно потому, что я собираюсь написать один, который соответствует обоим.

Дело в том, что каждый раз, когда выимеют /* и // и буквальные строки, «мешающие» друг другу, всегда приоритет имеет тот, который начинается первым.Это очень удобно, потому что именно так работают регулярные выражения: сначала найдите первое совпадение.

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

var blockComments = @"/\*(.*?)\*/";
var lineComments = @"//(.*?)\r?\n";
var strings = @"""((\\[^\n]|[^""\n])*)""";
var verbatimStrings = @"@(""[^""]*"")+";

Чтобы ответить на вопросв заголовке (комментарии полосы) нам нужно:

  • Заменить комментарии блока ничем
  • Заменить комментарии строки новой строкой (поскольку регулярное выражение использует новую строку)
  • Храните буквенные строки там, где они есть.

Regex.Replace может сделать это легко, используя функцию MatchEvaluator:

string noComments = Regex.Replace(input,
    blockComments + "|" + lineComments + "|" + strings + "|" + verbatimStrings,
    me => {
        if (me.Value.StartsWith("/*") || me.Value.StartsWith("//"))
            return me.Value.StartsWith("//") ? Environment.NewLine : "";
        // Keep the literal strings
        return me.Value;
    },
    RegexOptions.Singleline);

Я запускал этот код на всех примерахтот Holystream предоставил и различные другие случаи, о которых я мог думать, и это работает как очарование.Если вы можете привести пример с ошибкой, я с радостью скорректирую код для вас.

7 голосов
/ 19 августа 2010

Прежде чем реализовать это, вам необходимо сначала создать для него тестовые случаи

  1. Простые комментарии / * * /, //, ///
  2. Многострочные комментарии /* This \ nis \ na \ ntest * /
  3. Комментарии после строки кода var a = "apple";// test или / * test * /
  4. Комментарии в комментариях / * Это // тест /, или // Этот / тест * /
  5. Простые не комментарии, которые выглядят как комментарии и появляются в кавычках var comment = "/ * Это тест * /", или var url = "http://stackoverflow.com";
  6. Сложные не комментарии, похожие на комментарии: var abc= @ "this / * \ n - это комментарий в кавычках \ n * /", с пробелами или без пробелов между "и / * или * / и"

Возможно, есть и другие случаи.

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

Решение этого с помощью одного только регулярного выражения, вероятно, будет очень трудным и ошибочным-простой, трудный для тестирования и трудный для поддержки вами и другими программистами.

6 голосов
/ 03 февраля 2012

Вы можете маркировать код с помощью выражения вроде:

@(?:"[^"]*")+|"(?:[^"\n\\]+|\\.)*"|'(?:[^'\n\\]+|\\.)*'|//.*|/\*(?s:.*?)\*/

Это также будет соответствовать некоторым недопустимым escape-символам / структурам (например, 'foo'), но, вероятно, будет соответствовать всем действительным токенам интереса (еслиЯ кое-что забыл), таким образом, работая хорошо для действующего кода.

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

static string StripComments(string code)
{
    var re = @"(@(?:""[^""]*"")+|""(?:[^""\n\\]+|\\.)*""|'(?:[^'\n\\]+|\\.)*')|//.*|/\*(?s:.*?)\*/";
    return Regex.Replace(code, re, "$1");
}

Пример приложения :

using System;
using System.Text.RegularExpressions;

namespace Regex01
{
    class Program
    {
        static string StripComments(string code)
        {
            var re = @"(@(?:""[^""]*"")+|""(?:[^""\n\\]+|\\.)*""|'(?:[^'\n\\]+|\\.)*')|//.*|/\*(?s:.*?)\*/";
            return Regex.Replace(code, re, "$1");
        }

        static void Main(string[] args)
        {
            var input = "hello /* world */ oh \" '\\\" // ha/*i*/\" and // bai";
            Console.WriteLine(input);

            var noComments = StripComments(input);
            Console.WriteLine(noComments);
        }
    }
}

Выход:

hello /* world */ oh " '\" // ha/*i*/" and // bai
hello  oh " '\" // ha/*i*/" and
1 голос
/ 15 мая 2013

Я нашел это в http://gskinner.com/RegExr/ (названный ".Net Comments aspx")

(//[\t|\s|\w|\d|\.]*[\r\n|\n])|([\s|\t]*/\*[\t|\s|\w|\W|\d|\.|\r|\n]*\*/)|(\<[!%][ \r\n\t]*(--([^\-]|[\r\n]|-[^\-])*--[ \r\n\t%]*)\>)

Когда я проверяю его, кажется, что он удаляет все // комментарии и / * комментарии * / как следует, оставляя эти внутри кавычки позади.

Много не тестировал, но, кажется, работает довольно хорошо (хотя это ужасная чудовищная линия регулярных выражений).

0 голосов
/ 24 декабря 2013

Также см. Мой проект для минимизации кода C #: CSharp-Minifier

Помимо удаления комментариев, пробелов и разрывов строк из кода, в настоящее время он может сжимать локальную переменнуюимена и делать другие минимизации.

0 голосов
/ 17 сентября 2013

для комментариев блока (/ * ... * /) вы можете использовать этот опыт:

/\*([^\*/])*\*/

также будет работать с многострочными комментариями.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...