为什么Regex Matches上的For循环很慢

本文关键字:循环 For 上的 Regex Matches 为什么 | 更新日期: 2023-09-27 18:29:00

我有以下代码:

        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"。对于非常大的字符串,执行需要一分钟以上的时间。我很困惑为什么以及该怎么做才能解决这个问题。

为什么Regex Matches上的For循环很慢

为了找到计数,必须找到所有匹配项才能进行计数。考虑到你无论如何都要在三点后停下来,这似乎有点毫无意义。

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>类型。)

来自MSDN:

Matches方法使用延迟求值来填充返回的MatchCollection对象。访问此集合的成员,例如MatchCollection.Count和MatchCollection.CopyTo导致集合以便立即填充。为了利用懒惰的评估应该通过在中使用foreach等构造来迭代集合C#

一句话:将代码更改为使用foreach

另一种方法是调用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();
    }