Подтвердить что ты не робот

Регулярное выражение для комментариев линии линии от С#

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

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

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

И я могу полностью комбинировать комментарии по линии (//комментарий), используя это регулярное выражение с помощью 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] не будут.

4b9b3361

Ответ 1

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

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

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

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, и в различных других случаях, о которых я мог думать, и он работает как шарм. Если вы можете предоставить пример, где он терпит неудачу, я с удовольствием настрою код для вас.

Ответ 2

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

  • Простые комментарии /* */,//,///
  • Многострочные комментарии /* Это\nis\na\ntest */
  • Комментарии после строки кода var a = "apple"; //test или/* test */
  • Комментарии в комментариях /* Это//является тестом /, или//Это/является тестом */
  • Простые комментарии, которые выглядят как комментарии, и отображаются в кавычках var comment = "/* Это тест */", или var url = "/fooobar.com/...";
  • Сложные не комментарии taht выглядят как комментарии: var abc = @ "this/*\n - комментарий в цитате \n */", с пробелами или без пробелов между "и/* или * и"

Есть, вероятно, больше случаев.

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

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

Ответ 3

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

@(?:"[^"]*")+|"(?:[^"\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

Ответ 4

Я нашел это в 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%]*)\>)

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

Не тестировал его много, но, похоже, работает очень хорошо (хотя его ужасная чудовищная линия регулярного выражения).

Ответ 5

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

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

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

Ответ 6

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

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