2011-10-04 55 views
12

过去一周我一直在用正则表达式做一些工作,并设法取得了很多进展,但是,我仍然相当n00b。我有一个正则表达式用C#编写:在C#中正则表达式缓慢运行

string isMethodRegex = 
    @"\b(public|private|internal|protected)?\s*(static|virtual|abstract)?"+ 
    @"\s*(?<returnType>[a-zA-Z\<\>_1-9]*)\s(?<method>[a-zA-Z\<\>_1-9]+)\s*\"+ 
    @"((?<parameters>(([a-zA-Z\[\]\<\>_1-9]*\s*[a-zA-Z_1-9]*\s*)[,]?\s*)+)\)"; 
IsMethodRegex = new Regex(isMethodRegex); 

出于某种原因,称正则表达式IsMethodRegex.IsMatch()它挂起超过30秒以下字符串时:

"\t * Returns collection of active STOP transactions (transaction type 30) " 

有谁如何正则表达式的内部工作,以及为什么这匹配这个字符串,而不是其他人。我和它玩过一段时间,发现如果我拿出*和括号,那么它运行良好。也许正则表达式写得不好?

任何帮助将非常感激。

+2

你试过编译正则表达式吗?其中一个构造函数重载提供了这种能力。 –

+0

@Steve:我只是测试一下自己,编译完成后仍然需要很长时间。我可以在LinqPad的自己的机器上重现很长时间。 – mellamokb

+2

我知道这是在旁边,但你的正则表达式对我来说很脆弱。不知何故,我认为性能是你的问题中最少的。 – ChaosPandion

回答

3

编辑:我认为性能问题是以<parameters>匹配组的方式完成的。我已重新排列以匹配第一个参数,然后匹配任意数量的连续参数,或者根本不选。此外,我已经改变了\s*参数类型和名称之间\s+(我认为这是负责回溯,因为它允许没有空格的很多,让object可以为object\s*匹配没有空格匹配),而它似乎运行速度快了很多:

string isMethodRegex = 
    @"\b(public|private|internal|protected)?\s*(static|virtual|abstract)?"+ 
    @"\s*(?<returnType>[a-zA-Z\<\>_1-9]*)\s*(?<method>[a-zA-Z\<\>_1-9]+)\s*\"+ 
    @"((?<parameters>((\s*[a-zA-Z\[\]\<\>_1-9]*\s+[a-zA-Z_1-9]*\s*)"+ 
    @"(\s*,\s*[a-zA-Z\[\]\<\>_1-9]*\s+[a-zA-Z_1-9]*\s*)*\s*))?\)"; 

编辑:作为正式指出的@丹,以下是简单的,因为正则表达式可以提前退出。

这的确是一个非常奇怪的局面,但如果我删除了两个可选的匹配开头(公共/私营/内部/保护和静态/虚拟/抽象的),那么它开始几乎瞬间再次运行:

string isMethodRegex = 
    @"\b(public|private|internal|protected)\s*(static|virtual|abstract)"+ 
    @"(?<returnType>[a-zA-Z\<\>_1-9]*)\s(?<method>[a-zA-Z\<\>_1-9]+)\s*\"+ 
    @"((?<parameters>(([a-zA-Z\[\]\<\>_1-9]*\s*[a-zA-Z_1-9]*\s*)[,]?\s*)+)\)"; 
var IsMethodRegex = new Regex(isMethodRegex); 

string s = "\t * Returns collection of active STOP transactions (transaction type 30) "; 

Console.WriteLine(IsMethodRegex.IsMatch(s)); 

从技术上讲,你可以分成四个单独的正则表达式来处理这种特殊情况。但是,当您尝试处理越来越复杂的场景时,您可能会一次又一次地遇到此性能问题,因此这可能不是理想的方法。

+0

这是'假'的结果,对吗?它可以立即排除比赛,因为它不是以'p'或'i'开头,所以这是一个简单的搜索。 –

+0

@丹:的确,你是对的。我怀疑这与''部分完成的方式有关。 – mellamokb

3

我改变了一个或多个(*)与1或更多(+)匹配,其中我认为它对您的正则表达式有意义(它更适合于Java和C#而不是VB.NET ):

string isMethodRegex = 
    @"\b(public|private|internal|protected)?\s*(static|virtual|abstract)?" + 
    @"\s*(?<returnType>[a-zA-Z\<\>_1-9]+)\s+(?<method>[a-zA-Z\<\>_1-9]+)\s+\" + 
    @"((?<parameters>(([a-zA-Z\[\]\<\>_1-9]+\s+[a-zA-Z_1-9]+\s*)[,]?\s*)+)\)"; 

现在速度很快。

请检查它是否仍然返回您期望的结果。

对于坏的正则表达式的一些背景,请看here

1

你试过编译你的Regex了吗?

string pattern = @"\b[at]\w+"; 
RegexOptions options = RegexOptions.IgnoreCase | RegexOptions.Compiled; 
string text = "The threaded application ate up the thread pool as it executed."; 
MatchCollection matches; 

Regex optionRegex = new Regex(pattern, options); 
Console.WriteLine("Parsing '{0}' with options {1}:", text, options.ToString()); 
// Get matches of pattern in text 
matches = optionRegex.Matches(text); 
// Iterate matches 
for (int ctr = 1; ctr <= matches.Count; ctr++) 
    Console.WriteLine("{0}. {1}", ctr, matches[ctr-1].Value); 

然后正则表达式只在第一次执行时慢。

+0

我们已经试过了,没有区别。事实上,有一个回答说,在一段时间之前,作者删除了同样的事情。 – mellamokb