当前位置:  开发笔记 > 编程语言 > 正文

改进/修复C样式块注释的正则表达式

如何解决《改进/修复C样式块注释的正则表达式》经验,为你挑选了2个好方法。

我正在编写(在C#中)一个简单的解析器来处理一个看起来很像经典C的脚本语言.

在我拥有的一个脚本文件中,我用来识别/*阻止注释*/的正则表达式将进入某种无限循环,占用100%的CPU.

我正在使用的正则表达式是这样的:

/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/

有关为什么会被锁定的任何建议?

或者,我可以使用的另一个正则表达式是什么?

更多信息:

使用面向.NET 3.5的C#3.0;

我正在使用Regex.Match(string,int)方法在字符串的特定索引处开始匹配;

我让程序运行了一个多小时,但比赛没有完成;

传递给Regex构造函数的选项是RegexOptions.MultilineRegexOptions.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,所以我不能说哪个版本对于该引擎更快.



1> Alan Moore..:

我在你的正则表达式中遇到的一些问题:

|[\r\n]你的正则表达式中不需要序列; 否定的字符类[^*]匹配除了*包括行分隔符在内的所有内容.它只是.(点)元字符与那些不匹配.

一旦你进入评论,你必须寻找的唯一一个字符是星号; 只要你没有看到其中一个,你就可以吞噬你想要的任意数量的角色.这意味着[^*]当你可以使用它时使用是没有意义的[^*]+.事实上,你可以把它放在一个原子组中 - (?>[^*]+)因为一旦你匹配它们,你就没有任何理由放弃任何那些非星号.

过滤掉无关的垃圾,你最外面的parens里面的最后一个选择是\*+[^*/],这意味着"一个或多个星号,后跟一个不是星号或斜线的字符".这将始终与注释末尾的星号相匹配,并且它将始终必须再次放弃,因为下一个字符是斜杠.事实上,如果有20个星号导致最后的斜线,那么正则表达式的那部分将与它们全部匹配,那么它将一个接一个地给它们全部.然后最后的部分 - \*+/将匹配它们保持.

为了获得最佳性能,我会使用这个正则表达式:

/\*(?>(?:(?>[^*]+)|\*(?!/))*)\*/

这将非常快速地匹配格式良好的注释,但更重要的是,如果它开始匹配不是有效注释的内容,它将尽快失败.


由David提供,这是一个匹配任何嵌套级别的嵌套注释的版本:

(?s)/\*(?>/\*(?)|\*/(?<-LEVEL>)|(?!/\*|\*/).)+(?(LEVEL)(?!))\*/

它使用.NET的平衡组,因此它不适用于任何其他风格.为了完整起见,这是另一个版本(来自RegexBuddy的库),它使用Perl,PCRE和Oniguruma/Onigmo支持的递归组语法:

/\*(?>[^*/]+|\*[^/]|/[^*])*(?>(?R)(?>[^*/]+|\*[^/]|/[^*])*)*\*/



2> ridgerunner..:

不不不!没有其他人阅读掌握正则表达式(第3版)!?在此,Jeffrey Friedl检查了这个确切的问题,并以此为例(第272-276页)来说明他的"展开循环"技术.他对大多数正则表达式引擎的解决方案是这样的:

/\*[^*]*\*+(?:[^*/][^*]*\*+)*/

但是,如果正则表达式引擎被优化以处理惰性量词(如Perl的那样),则最有效的表达式更简单(如上所述):

/\*.*?\*/

(当然应用等效的's'"点匹配所有"修饰符.)请注意,我不使用.NET,所以我不能说哪个版本对于该引擎更快.

推荐阅读
臭小子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有