Регулярное выражение для комментариев линии линии от С#
Я работаю над подпрограммой, чтобы снимать комментарии блоков или строк от некоторого кода С#. Я просмотрел другие примеры на сайте, но не нашел точного ответа, который я ищу.
Я могу полностью комбинировать комментарии блоков (/* 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]
не будут.
Ответы
Ответ 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
Помимо удаления комментариев, пробелов и разрывов строк из кода, в настоящее время он способен сжимать имена локальной переменной и делать еще одно предупреждение.