1

我正在为 MVC C# 应用程序开发一个搜索功能,该应用程序将通过过滤器放置一个(可能很大的)文本块,并在给定搜索查询的情况下,将<span>在每个搜索词之前和之后放置一个具有突出显示样式的 html。

我有一个简单的算法,但我感觉它会很慢,可能是因为需要创建的字符串数量(2 * 匹配数)。

public static string Surround(string original, string head, string tail, string match, StringComparison comparer)
{
    var ret = original;

    if (ret.IndexOf(match, 0, comparer) != -1)
    {
        var lastIndex = 0;

        while ((lastIndex = ret.IndexOf(match, lastIndex, comparer)) != -1)
        {
            ret = ret.Insert(lastIndex, head);
            var tailIndex = lastIndex + match.Length + head.Length;
            lastIndex = tailIndex;
            ret = ret.Insert(tailIndex, tail);
        }
    }

    return ret;
}

我想知道是否有人可以为更好的算法提供一些提示,以更好地处理大块文本?我正在考虑使用字符串生成器,但我也想到我可能会以完全错误的方式处理这个问题。任何见解将不胜感激。

4

4 回答 4

6

正则表达式将完成这项工作,并且代码应该简单得多。但是,您需要进行测试以确定它是否确实提供了更好的性能。像这样的东西:

public static string Surround(
    string original, string head, string tail, string match)
{
    return Regex.Replace(
        original, match, head + "$0" + tail, RegexOptions.IgnoreCase);
}

如果您可以在保存 2N 个字符串连接时传递整个替换器,那就更好了:

public static string Surround(string original, string replacer, string match)
{
    return Regex.Replace(original, match, replacer, RegexOptions.IgnoreCase);
}

Surround("foo bar baz", "<span>$&</span>", "bar");  //call like so
于 2009-02-20T15:21:11.543 回答
1

StringBuilder 当然会快得多,但是当您执行 .Insert 时,您每次都会移动大量数据。因此,最好仅使用 .Append 在 StringBuilder 中构建结果。不是。插入。

但是,您也应该能够为此使用正则表达式,尽管我不知道语法(当我需要时,我使用一个名为 RegEx Buddy 的出色工具来构建我的正则表达式。)。

编辑:这个世界上很少有人能够区分正则表达式和传输线噪声。:-)

于 2009-02-20T15:09:37.360 回答
0

卢克的回答很好,但你可能想先转义“匹配”中的任何特殊字符,以防有人使用 .\^$? 等在他们的搜索中(除非你当然想允许)。

ETA:允许特殊字符将允许更强大的搜索,但也会导致意外输出,因为找到的文本将被替换为模式而不是实际匹配的文本。

于 2009-02-20T15:34:25.753 回答
0

RegEx 解决方案绝对比我制作的更优雅。但是,使用 StringBuilder 通常要快一些,并且不需要对搜索词和前/后修复进行正则表达式转义。

private static string Surround(string original, string head, string tail, string match, StringComparison comparisonType)
{
  if (string.IsNullOrEmpty(original) || string.IsNullOrEmpty(match) || (string.IsNullOrEmpty(head) && string.IsNullOrEmpty(tail)))
    return original;

  var resultBuilder = new StringBuilder();
  int matchLength = match.Length;
  int lastIdx = 0;

  for (;;)
  {
    int curIdx = original.IndexOf(match, lastIdx, comparisonType);

    if (curIdx > -1)
      resultBuilder
        .Append(original, lastIdx, curIdx - lastIdx)
        .Append(head)
        .Append(original, curIdx, matchLength)
        .Append(tail);
    else
      return resultBuilder.Append(original.Substring(lastIdx)).ToString();

    lastIdx = curIdx + matchLength;
  }
}

我希望你可以使用它。

更新 做一些性能测试似乎我的解决方案只有在您搜索“短”字时才会更快。如果单词很长(即长度> 7)正则表达式获胜,但如果单词很短(即长度<7),那么我的解决方案将获胜。有谁知道这是为什么?什么操作对长度如此敏感?是 IndexOf(string, int, int) 还是 Append(string, int, int)?

于 2009-02-20T17:44:08.737 回答