使用正则表达式删除注释

时间:2017-02-17 00:19:49

标签: c# regex

我正在构建一个解析器,我想删除各行的注释。例如,

@Override
public String toString(){ return String.format("%-40s %4d", title, n); }

评论标记为variable = "some//thing" ////actual comment 。在这种情况下,//将包含variable,其他所有内容都将被忽略。我计划使用正则表达式替换它。目前我使用"some//thing"作为正则表达式。但是,替换它会完全取代(".*"|[ \t])*(\/\/.*)

我无法弄清楚我应该使用的正则表达式。谢谢你的帮助。

其他信息 - 我正在使用带有netcoreapp 1.1.0的C#

编辑 - 某些情况可能只是像"some//thing" ////actual comment这样的评论。字符串也可能包含转义引号。

2 个答案:

答案 0 :(得分:1)

这是丑陋的正则表达式模式。我相信它会运作良好。我已经尝试过我能想到的每个病态示例,包括包含语法错误的行。例如,引用的字符串引号太多或太少,或者具有双重转义引号,因此转义。并且在评论中引用了字符串,当我想提醒自己有其他选择时,我知道这些字符串。

它跳出的唯一时间是在看似引用的字符串中有一个双斜杠,并且某种方式该字符串格式错误并且双斜杠在合适的引用部分之外合法地结束。从语法上来说,这是一个有效的评论,即使不是程序员的意图。因此,从程序员的角度来看,这是错误的,但根据规则,它确实是一个评论。这意味着,该模式似乎只会绊倒。

使用时,模式将返回行的非注释部分。该模式中包含换行符\n,以允许将其应用于整个文件。如果系统以其他方式解释换行符,您可能需要修改它,例如\r\r\n。要在单线模式下使用它,您可以选择删除它。它在单行中的字符17和18处,并且在多行版本的第五行,第6和第7个打印字符上。但是,您可以安全地将其保留在那里,因为在单行模式下它没有任何区别,并且在多行模式下,它将返回一行代码行的换行符,这些代码行为空白,或者在第一列中开始注释。如果将结果写入新文件,这将使原始版本和规定版本中的行号保持相同。使比较变得容易。

此模式的一个主要警告:它使用的分组结构在正则表达式引擎中具有不同级别的支持。我相信这里使用的是,只有.NET和PCRE引擎才能接受YMMV。它是一种三级类型:(?(_condition_)_then_|_else_)_condition_模式被视为零宽度断言。如果模式匹配,则在尝试匹配中使用_then_模式,否则使用_else_模式。如果没有这种结构,那么这种模式就会发展到不寻常的长度,并且在我的一些病理测试案例中仍然失败。

这里介绍的模式是正则表达式引擎需要看到的。我不是 C#程序员,所以我不知道转义引用字符串的所有细微差别。将此模式添加到您的代码中,以便正则表达式引擎正确地看到所有反斜杠和引号仍然取决于您。也许C#具有Perl heredoc语法的等价物。

这是使用的单线模式:

^((?:(?:(?:[^"'/\n]|/(?!/))*)(?("(?=(?:\\\\|\\"|[^"])*"))(?:"(?:\\\\|\\"|[^"])*")|(?('(?=(?:\\\\|\\'|[^'])*'))(?:'(?:\\\\|\\'|[^'])*')|(?(/)|.))))*)

如果要使用ignore pattern whitespace选项,可以使用此版本:

(?x) # Turn on the ignore white space option
^( # Start the only capturing group
    (?: # A non-capturing group to allow for repeating the logic
        (?: # Capture either of the two options below
            [^"'/\n] # Capture everything not a single quote, double quote, a slash, or a newline
            | # OR
            /(?!/) # Capture a slash not followed by a slash [slash an negative look-ahead slash]
        )* # As many times as possible, even if none
        (?(" # Start a conditional match for double-quoted strings
                (?=(?:\\\\|\\"|[^"])*") # Followed by a properly closed double-quoted string
            ) # Then
            (?:"(?:\\\\|\\"|[^"])*") # Capture the whole double-quoted string
            | # Otherwise
            (?(' # Start a conditional match for single-quoted strings
                (?=(?:\\\\|\\'|[^'])*') # Followed by a properly closed single-quoted string
                ) # Then
                (?:'(?:\\\\|\\'|[^'])*') # Capture the whole double-quoted string
                | # Otherwise
                (?([^/]) # If next character is not a slash
                .) # Capture that character, it is either a single quote, or a double quote not part of a properly closed
            ) # end the conditional match for single-quoted strings
        ) # End the conditional match for double-quoted strings
    )* # Close the repeating non-capturing group, capturing as many times as possible, even if none
) # Close the only capturing group

这允许您的代码解释这种怪异,以便当其他人看到它时,或者在几个月内您必须自己处理它时,那里没有WTF时刻。我认为这些评论很好地解释了它,但你可以随意改变它们。

如上所述,条件匹配分组的支持有限。它将失败的一个地方是您在之前的评论中链接到的网站。由于您正在使用C#,我选择在.NET Regex Tester中进行测试,这可以处理这些构造。它也包括一个很好的参考。如果侧面有适当的选择,您可以测试上面的任一版本,并进行实验。考虑到它的复杂性,我建议在某处测试来自文件的数据,以及你可以想象的任何边缘情况和病理测试。

为了兑换这个小模式,有一个更大的模式来测试电子邮件地址是78列81行,有几十个字符备用。 (我建议使用,或任何其他正则表达式,用于测试电子邮件地址。错误的工具。)如果你想吓唬自己,请在{{3}上查看它网站。我跟那个没什么关系!!

答案 1 :(得分:0)

"[^"\\]*(?:\\[\W\w][^"\\]*)*"|(\/\/.*)

标志:全球

匹配完整字符串或评论。

第1组:评论。

因此,如果没有评论,请使用相同的匹配文本替换。否则,在评论本身上做你的事。