【问题标题】:Why is For loop on Regex Matches slow?为什么正则表达式匹配上的 For 循环很慢?
【发布时间】:2013-08-25 06:45:25
【问题描述】:

我有以下代码:

        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 个词,在搜索词之后得到 1-6 个词。执行代码时,性能会影响 for 循环“matches.Count”。对于非常大的字符串,它需要一分钟以上的时间来执行。我很困惑为什么以及如何解决这个问题。

【问题讨论】:

    标签: c# asp.net-mvc regex


    【解决方案1】:

    为了找到计数,必须找到所有个匹配项才能对它们进行计数。反正三点之后你就要停下来,这似乎有点没有意义。

    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&lt;T&gt; 类型。 )

    【讨论】:

    • 谢谢!深夜把我的头撞在墙上。这大大提高了性能。与 58.67 秒相比,我的加载时间约为 5 秒
    【解决方案2】:

    来自 MSDN:

    Matches 方法使用惰性求值来填充返回的 匹配集合对象。访问此集合的成员,例如 MatchCollection.Count 和 MatchCollection.CopyTo 导致集合 立即填充。为了利用惰性求值,你 应该使用 foreach 等构造来迭代集合 C#

    底线:更改您的代码以使用foreach

    【讨论】:

      【解决方案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();
          }
      

      【讨论】:

      • 我想你的意思是Regex.Match 不是Regex.Matches 在第一行?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-04
      • 2011-08-11
      • 2018-08-24
      相关资源
      最近更新 更多