为什么正则表达式上的For循环缓慢?

时间:2013-08-25 06:45:25

标签: c# asp.net-mvc regex

我有以下代码:

        string pattern = @"(?:\S+\s){1,6}\S*" + search + @"\S*(?:\s\S+){1,6}";
        String dbContents = row[2].ToString();
        var matches = Regex.Matches(dbContents, pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
        for (int i = 0; i < matches.Count; i++)
        {
            if (i == 3)
                break;

            Contents += String.Format("... {0} ...", matches[i].Value);
        } 

我想要完成的是在搜索词之前获得一到六个单词,在搜索词之后获得1-6个单词。执行代码时,性能在for循环“matches.Count”上命中。对于非常大的字符串,它需要花费一分钟来执行。我很困惑为什么以及如何解决这个问题。

3 个答案:

答案 0 :(得分:10)

为了找到计数,必须找到 all 匹配才能对它们进行计数。鉴于你无论如何都要在三点之后停下来,这似乎有点无意义。

MatchCollection的延迟评估与LINQ中的Take方法结合使用,只进行前三次匹配。通常,在循环中使用StringBuilder而不是字符串连接也是个好主意:

StringBuilder builder = new StringBuilder(...);
foreach (var match in matches.Cast<Match>().Take(3))
{
    builder.AppendFormat("... {0} ...", matches[i].Value);
}

StringBuilder更改可能不会在这里产生太大的影响,但这是一个很好的习惯。Cast方法是必需的,因为Enumerable.Take仅适用于通用IEnumerable<T>类型。)

答案 1 :(得分:3)

来自MSDN:

  

Matches方法使用延迟评估来填充返回的   MatchCollection对象。访问此集合的成员,例如   MatchCollection.Count和MatchCollection.CopyTo导致集合   立即填充。为了利用懒惰的评估,你   应该使用诸如foreach之类的构造来迭代集合   C#

底线:将代码更改为使用foreach

答案 2 :(得分:3)

另一种方法是拨打Match,然后拨打NextMatch,如下所示:

    var match = Regex.Match(dbContents, pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
    for (int i = 0; i < 3 && match.Success; i++)
    {
        Contents += String.Format("... {0} ...", matches[i].Value);
        match = match.NextMatch();
    }