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;
}

大きなテキストのチャンクに対してより良いパフォーマンスを発揮するより良いアルゴリズムのヒントを誰かが与えることができるかどうか疑問に思っていますか? stringbuilder を使用することを考えていましたが、まったく間違った方法でこれに取り組んでいる可能性があることにも気付きました。どんな洞察も大歓迎です。

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 で結果を構築することをお勧めします。ではありません。挿入します。

ただし、これにはRegularExpressionも使用できるはずですが、構文を暗記することはできません(必要な場合は、RegEx Buddyという素晴らしいツールを使用して正規表現を構築します)。

編集: この世界では、正規表現と通信回線のノイズを区別できる人はほとんどいません。:-)

于 2009-02-20T15:09:37.360 に答える
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 に答える
0

ルークの答えは良いですが、誰かが。\ ^ $を使用する場合に備えて、最初に「一致」の特殊文字をエスケープすることをお勧めします。彼らの検索など(もちろんそれを許可したい場合を除く)。

ETA:特殊文字を許可すると、より強力な検索が可能になりますが、見つかったテキストが実際に一致するテキストではなくパターンに置き換えられるため、予期しない出力も発生します。

于 2009-02-20T15:34:25.753 に答える