C#中的正则表达式运行缓慢

时间:2011-10-04 00:02:37

标签: c# regex performance

过去一周我一直在用正则表达式做一些工作并且取得了很大的进步,但是,我仍然相当n00b。我有一个用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) "

有没有人如何使用正则表达式的内部工作以及为什么在匹配此字符串而不是其他字符串时会如此慢。我玩过它,发现如果我取出*和括号,那么它运行正常。也许正则表达式写得不好?

任何帮助都会非常感激。

3 个答案:

答案 0 :(得分:3)

编辑:我认为性能问题与<parameters>匹配组的完成方式有关。我重新排列以匹配第一个参数,然后匹配任意数量的连续参数,或者可选地根本不匹配。此外,我已将参数类型和名称之间的\s*更改为\s+(我认为这导致很多回溯,因为它不允许空格,因此object可以匹配为{{ 1}}和obj ect匹配无空格)并且似乎运行得更快:

\s*

编辑:正如@Dan正式指出的那样,以下只是因为正则表达式可以提前退出。

这确实是一个非常奇怪的情况,但如果我在开头删除两个可选匹配(对于public / private / internal / protected和static / virtual / abstract),那么它几乎立即开始运行:

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*))?\)";

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

答案 1 :(得分:3)

我改变了一些0或更多(*)匹配与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

答案 2 :(得分:1)

您是否尝试过编译正则表达式?

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);

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