为什么Regex挂在C#

时间:2014-12-02 16:52:29

标签: c# regex

我有一个相当不错的搜索,虽然有很多类似的问题,但我不相信答案是适用的。

我有一个相当低效的正则表达式搜索一个相当大的字符串。我已经使用精确的正则表达式和字符串在http://regexpal.com中对其进行了测试,并且几乎立即回复了正确的答案。

具有相同输入的C#Regex模块挂起 - 或者至少我已经离开它10分钟来完成regexpal在几分之一秒内可以做的事情。

正则表达式的C#实现是否比http://regexpal.com效率低,还是真的悬挂?正则表达式是搜索两个由未知行数分隔的关键字:

"KEYWORD1(.|\r|\n)+KEYWORD2\t +.+"

字符串长830行,每行约30个字符。

3 个答案:

答案 0 :(得分:3)

根据Regular Expression上的文档,. 匹配除\n 之外的任何单个字符。这意味着.(与Java中的\r(默认模式),JavaScript等不匹配)与.NET中的\r匹配。

你的正则表达式有效地允许2个分支用于相同的字符\r。输入中\r越多,运行正则表达式所需的时间就越长。在输入失败时,它将根据输入中\r的数量导致指数复杂性。

请注意,regexpal是一个JavaScript正则表达式测试程序,如上所述,JavaScript中的.会排除\r\n(以及其他一些行分隔符)。由于它们匹配的内容没有重叠,因此每个角色最多只能有一个分支。

一种解决方案是将(.|\r|\n)+替换为(?s:.+)s标志将有效地使.匹配任何字符,无例外。任何角色只有一个分支,因此没有指数回溯。

在这种情况下,

 +.+不会导致效率低下,因为它已经处于模式的最后。但是,如果还有其他内容,它可能会导致问题(二次复杂性)。例如,如果最后有$,那么在失败的情况下,当模式 +.+$与具有大量空格的后缀匹配时,后跟最后的换行符,则未优化引擎会尝试各种方法将连续的空格分成两部分。

答案 1 :(得分:2)

正如评论中所述,正则表达式的一个常见问题是有一个模式:

Word1.+Word2

因为如果你的文字很大并且有类似的东西:

Word1 ... Word1 ... Word2 ... Word2 ... Word1 .... Word2 ... Word2

您的所有组合与Word1匹配,以Word2结尾 - 即使Word1Word2介于它们之间

通常情况下,这不是您正在寻找的内容,并希望在起点和终点之间设置最短的字符集(或者不再显示Word1)。为此,你的正则表达式最好改为:

Word1.+?Word2

希望这是有道理的。

答案 2 :(得分:-1)

基本上,你的正则表达式是递归的。删除最终.+可以解决问题。以下是a good article关于避免它的问题。为什么.NET挂起?可能是因为它永远不会中止搜索。也许你使用的JavaScript解析器如果检测到太多步骤或者进入递归搜索太深,就会中止。