我正在编写(在C#中)一个简单的解析器来处理一个看起来很像经典C的脚本语言.
在我拥有的一个脚本文件中,我用来识别/*阻止注释*/的正则表达式将进入某种无限循环,占用100%的CPU.
我正在使用的正则表达式是这样的:
/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/
有关为什么会被锁定的任何建议?
或者,我可以使用的另一个正则表达式是什么?
更多信息:
使用面向.NET 3.5的C#3.0;
我正在使用Regex.Match(string,int)方法在字符串的特定索引处开始匹配;
我让程序运行了一个多小时,但比赛没有完成;
传递给Regex构造函数的选项是RegexOptions.Multiline
和 RegexOptions.IgnorePatternWhitespace
;
正则表达式适用于我的453个测试文件中的452个.
Alan Moore.. 16
我在你的正则表达式中遇到的一些问题:
|[\r\n]
你的正则表达式中不需要序列; 否定的字符类[^*]
匹配除了*
包括行分隔符在内的所有内容.它只是.
(点)元字符与那些不匹配.
一旦你进入评论,你必须寻找的唯一一个字符是星号; 只要你没有看到其中一个,你就可以吞噬你想要的任意数量的角色.这意味着[^*]
当你可以使用它时使用是没有意义的[^*]+
.事实上,你可以把它放在一个原子组中 - (?>[^*]+)
因为一旦你匹配它们,你就没有任何理由放弃任何那些非星号.
过滤掉无关的垃圾,你最外面的parens里面的最后一个选择是\*+[^*/]
,这意味着"一个或多个星号,后跟一个不是星号或斜线的字符".这将始终与注释末尾的星号相匹配,并且它将始终必须再次放弃,因为下一个字符是斜杠.事实上,如果有20个星号导致最后的斜线,那么正则表达式的那部分将与它们全部匹配,那么它将一个接一个地给它们全部.然后最后的部分 - \*+/
将匹配它们保持.
为了获得最佳性能,我会使用这个正则表达式:
/\*(?>(?:(?>[^*]+)|\*(?!/))*)\*/
这将非常快速地匹配格式良好的注释,但更重要的是,如果它开始匹配不是有效注释的内容,它将尽快失败.
由David提供,这是一个匹配任何嵌套级别的嵌套注释的版本:
(?s)/\*(?>/\*(?)|\*/(?<-LEVEL>)|(?!/\*|\*/).)+(?(LEVEL)(?!))\*/
它使用.NET的平衡组,因此它不适用于任何其他风格.为了完整起见,这是另一个版本(来自RegexBuddy的库),它使用Perl,PCRE和Oniguruma/Onigmo支持的递归组语法:
/\*(?>[^*/]+|\*[^/]|/[^*])*(?>(?R)(?>[^*/]+|\*[^/]|/[^*])*)*\*/
ridgerunner.. 14
不不不!没有其他人阅读掌握正则表达式(第3版)!?在此,Jeffrey Friedl检查了这个确切的问题,并以此为例(第272-276页)来说明他的"展开循环"技术.他对大多数正则表达式引擎的解决方案是这样的:
/\*[^*]*\*+(?:[^*/][^*]*\*+)*/
但是,如果正则表达式引擎被优化以处理惰性量词(如Perl的那样),则最有效的表达式更简单(如上所述):
/\*.*?\*/
(当然应用等效的's'"点匹配所有"修饰符.)请注意,我不使用.NET,所以我不能说哪个版本对于该引擎更快.
我在你的正则表达式中遇到的一些问题:
|[\r\n]
你的正则表达式中不需要序列; 否定的字符类[^*]
匹配除了*
包括行分隔符在内的所有内容.它只是.
(点)元字符与那些不匹配.
一旦你进入评论,你必须寻找的唯一一个字符是星号; 只要你没有看到其中一个,你就可以吞噬你想要的任意数量的角色.这意味着[^*]
当你可以使用它时使用是没有意义的[^*]+
.事实上,你可以把它放在一个原子组中 - (?>[^*]+)
因为一旦你匹配它们,你就没有任何理由放弃任何那些非星号.
过滤掉无关的垃圾,你最外面的parens里面的最后一个选择是\*+[^*/]
,这意味着"一个或多个星号,后跟一个不是星号或斜线的字符".这将始终与注释末尾的星号相匹配,并且它将始终必须再次放弃,因为下一个字符是斜杠.事实上,如果有20个星号导致最后的斜线,那么正则表达式的那部分将与它们全部匹配,那么它将一个接一个地给它们全部.然后最后的部分 - \*+/
将匹配它们保持.
为了获得最佳性能,我会使用这个正则表达式:
/\*(?>(?:(?>[^*]+)|\*(?!/))*)\*/
这将非常快速地匹配格式良好的注释,但更重要的是,如果它开始匹配不是有效注释的内容,它将尽快失败.
由David提供,这是一个匹配任何嵌套级别的嵌套注释的版本:
(?s)/\*(?>/\*(?)|\*/(?<-LEVEL>)|(?!/\*|\*/).)+(?(LEVEL)(?!))\*/
它使用.NET的平衡组,因此它不适用于任何其他风格.为了完整起见,这是另一个版本(来自RegexBuddy的库),它使用Perl,PCRE和Oniguruma/Onigmo支持的递归组语法:
/\*(?>[^*/]+|\*[^/]|/[^*])*(?>(?R)(?>[^*/]+|\*[^/]|/[^*])*)*\*/
不不不!没有其他人阅读掌握正则表达式(第3版)!?在此,Jeffrey Friedl检查了这个确切的问题,并以此为例(第272-276页)来说明他的"展开循环"技术.他对大多数正则表达式引擎的解决方案是这样的:
/\*[^*]*\*+(?:[^*/][^*]*\*+)*/
但是,如果正则表达式引擎被优化以处理惰性量词(如Perl的那样),则最有效的表达式更简单(如上所述):
/\*.*?\*/
(当然应用等效的's'"点匹配所有"修饰符.)请注意,我不使用.NET,所以我不能说哪个版本对于该引擎更快.