正则表达式从C#剥离行注释

Wel*_*.59 40 .net c# regex

我正在编写一个例程来从一些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";
Run Code Online (Sandbox Code Playgroud)

块表达式匹配

/* remove block comments
else
{
    return "FIXED";
} // do not remove nested comments */
Run Code Online (Sandbox Code Playgroud)

这很好,但线条表达匹配

// remove whole line comments
// remove partial line comments
Run Code Online (Sandbox Code Playgroud)

// do not remove nested comments
Run Code Online (Sandbox Code Playgroud)

此外,如果我在行表达式中没有两次*/positive前瞻,则匹配

// do not remove nested comments *
Run Code Online (Sandbox Code Playgroud)

真的不想要.

我要的是将匹配字符,从与表达//,到行的末尾,但包含*/之间//线和结束.

另外,为了满足我的好奇心,任何人都能解释为什么我需要两次前瞻吗? (//((?!\*/).)*)[^\r\n]并且(//(.)*)(?!\*/)[^\r\n]都将包括*,但(//((?!\*/).)*)(?!\*/)[^\r\n](//((?!\*/).)*(?!\*/))[^\r\n]不会.

Tim*_*mwi 80

两个正则表达式(用于块和行注释)都有错误.如果你想我可以描述的错误,但我觉得它可能是更有效率,如果我编写一个新的,尤其是因为我打算写一个匹配A一个.

问题是,每次你有时间/*//和文字字符串"干扰"互相,它始终是首先启动的一个优先.这非常方便,因为这正是正则表达式的工作方式:首先找到第一个匹配.

所以让我们定义一个匹配这四个标记中每个标记的正则表达式:

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

要回答标题中的问题(条带评论),我们需要:

  • 什么都没有替换块注释
  • 用换行符替换行注释(因为正则表达式使用换行符)
  • 将文字字符串保持原样.

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);
Run Code Online (Sandbox Code Playgroud)

我在Holystream提供的所有示例以及我能想到的各种其他案例上运行此代码,它就像一个魅力.如果您能提供失败的示例,我很乐意为您调整代码.

  • @Welton:嗯,你可以在结果上运行`Regex.Replace(@"^(\ s*\r?\n){2,}",Environment.Newline,RegexOptions.Multiline)`但是这样会删除空白双线,*没有*也有评论. (2认同)

Hol*_*eam 7

在实现此操作之前,您需要首先为它创建测试用例

  1. 简单评论/**/,//,///
  2. 多行评论/*这个\n是\na \ntest*/
  3. 代码行后面的注释var a ="apple"; // test或/*test*/
  4. 评论/*中的评论这是一个测试/,或//这个/是一个测试*/
  5. 简单的非注释看起来像注释,并出现在引号中var comment ="/*这是一个测试*/",或者var url =" http://stackoverflow.com ";
  6. 复杂的非注释看起来像注释:var abc = @"this/*\n是quote \n*/"中的注释,在"和/*或*/和"之间有或没有空格

那里可能有更多的案例.

一旦拥有了所有这些,就可以为每个人创建一个解析规则,或者对其中的一些进行分组.

单独使用正则表达式解决这个问题可能会非常困难且容易出错,难以测试,并且很难由您和其他程序员维护.


Qta*_*tax 6

您可以使用如下表达式对代码进行标记:

@(?:"[^"]*")+|"(?:[^"\n\\]+|\\.)*"|'(?:[^'\n\\]+|\\.)*'|//.*|/\*(?s:.*?)\*/
Run Code Online (Sandbox Code Playgroud)

它也会匹配一些无效的转义/结构(例如'foo'),但可能会匹配所有感兴趣的有效标记(除非我忘记了某些内容),因此适用于有效的代码.

在替换中使用它并捕获您想要保留的部件将为您提供所需的结果.即:

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

应用示例:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

hello /* world */ oh " '\" // ha/*i*/" and // bai
hello  oh " '\" // ha/*i*/" and
Run Code Online (Sandbox Code Playgroud)