我正在编写一个例程来从某些C#代码中去除或行注释。我查看了网站上的其他示例,但没有找到我正在寻找的完全答案。
我可以使用RegexOptions.Singleline的正则表达式完整地匹配块注释(/ * comment * /):
(/\*[\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]
则不会。
答案 0 :(得分:80)
两个正则表达式(用于块和行注释)都有错误。如果你想我可以描述错误,但我觉得如果我写新的错误可能会更有成效,特别是因为我打算写一个与之匹配的单一错误。
问题是,每当你有/*
和//
以及文字字符串相互“干扰”时,它总是首先以优先权开始。这非常方便,因为这正是正则表达式的工作方式:首先找到第一个匹配。
所以让我们定义一个匹配这四个标记中每一个的正则表达式:
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提供的所有示例和我能想到的各种其他案例上运行此代码,它就像一个魅力。如果您能提供失败的示例,我很乐意为您调整代码。
答案 1 :(得分:7)
在实现之前,您需要先为其创建测试用例
可能还有更多案例。
如果你拥有了所有这些,那么你可以为每个人创建一个解析规则,或者对其中的一些进行分组。
单独使用正则表达式来解决这个问题可能会非常困难且容易出错,难以测试,并且很难由您和其他程序员维护。
答案 2 :(得分:5)
您可以使用如下表达式对代码进行标记:
@(?:"[^"]*")+|"(?:[^"\n\\]+|\\.)*"|'(?:[^'\n\\]+|\\.)*'|//.*|/\*(?s:.*?)\*/
它也会匹配一些无效的转义/结构(例如'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
答案 3 :(得分:1)
我在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%]*)\>)
当我测试它时,它似乎删除了所有//注释和/ *注释* /,因为它应该留在引号内。
没有对它进行过多次测试,但似乎工作得很好(即使它是一个可怕的可怕的正则表达式)。
答案 4 :(得分:0)
另请参阅我的C#代码缩小项目:CSharp-Minifier
除了从代码中删除注释,空格和换行符之外,目前它还能够压缩局部变量名称并进行另一次缩小。
答案 5 :(得分:-1)
对于块注释(/ * ... * /),您可以使用此exp:
/\*([^\*/])*\*/
它也适用于多行注释。