5

我有以下代码:

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

4

3 回答 3

11

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

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

于 2013-08-25T06:57:08.020 回答
3

来自 MSDN:

Matches方法使用惰性求值来填充返回的 MatchCollection 对象。访问此集合的成员(例如 MatchCollection.Count 和 MatchCollection.CopyTo)会导致立即填充该集合。要利用惰性求值,您应该使用诸如foreachC# 中的构造来迭代集合

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

于 2013-08-25T07:01:46.017 回答
3

另一种方法是调用Matchthen 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();
    }
于 2013-08-25T07:11:57.787 回答