7

指定した文字以外のすべての文字を置き換える方法があります。例えば、

ReplaceNot("test. stop; or, not", ".;/\\".ToCharArray(), '*'); 

戻るだろう

"****.********;***,****".

さて、これは時期尚早の最適化の例ではありません。ネットワーク操作中に、このメソッドをかなりの回数呼び出します。長い文字列では、遅延が発生することがわかりました。これを削除すると少し効果がありました。これをスピードアップするための助けをいただければ幸いです。

    public static string ReplaceNot(this string original, char[] pattern, char replacement)
    {           
        int index = 0;
        int old = -1;

        StringBuilder sb = new StringBuilder(original.Length);

        while ((index = original.IndexOfAny(pattern, index)) > -1)
        {
            sb.Append(new string(replacement, index - old - 1));
            sb.Append(original[index]);
            old = index++;
        }

        if (original.Length - old > 1)
        {
            sb.Append(new string(replacement, original.Length - (old + 1)));
        }

        return sb.ToString();
    }

最後の # です。また、3K 文字列のテスト ケースを追加し、1M ではなく 100K 回実行して、これらの各スケールがどれだけうまくいくかを確認しました。唯一の驚きは、正規表現が他のものよりも「スケーリングが優れている」ことでしたが、最初は非常に遅いため、助けにはなりません:

ユーザー ショート * 1M ロング * 100K スケール
ジョン 319 2125 6.66
ルーク 360 2659 7.39
グッファ 409 2827 6.91
鉱山 447 3372 7.54
ダークジェントリー 1094 9134 8.35
マイケル 1591 12785 8.04
ピーター 21106 94386 4.47

更新: Peter のバージョンの正規表現の作成を静的変数にし、公平を期すために RegexOptions.Compiled に設定しました。

ユーザー ショート * 1M ロング * 100K スケール
ピーター 8997 74715 8.30

私のテストコードへのPastebinリンク、間違っている場合は修正してください: http://pastebin.com/f64f260ee

4

6 に答える 6

8

次のように Regex.Replace を使用できませんか:

Regex regex = new Regex(@"[^.;/\\]");
string s = regex.Replace("test. stop; or, not", "*");
于 2009-05-05T18:55:23.250 に答える
6

よし、~60KB の文字列では、これはあなたのバージョンよりも約 40% 速く実行されます:

public static string ReplaceNot(this string original, char[] pattern, char replacement)
{
    int index = 0;

    StringBuilder sb = new StringBuilder(new string(replacement, original.Length));

    while ((index = original.IndexOfAny(pattern, index)) > -1)
    {
        sb[index] = original[index++];
    }

    return sb.ToString();
}

トリックは、それらのほとんどが置き換えられるため、すべての置換文字で新しい文字列を初期化することです。

于 2009-05-05T18:55:49.177 に答える
4

これがより高速になるかどうかはわかりませんが、文字列ビルダーに追加できるように文字列を新しくすることを回避できます。

    public static string ReplaceNot(this string original, char[] pattern, char replacement)
    {
        StringBuilder sb = new StringBuilder(original.Length);

        foreach (char ch in original) {
            if (Array.IndexOf( pattern, ch) >= 0) {
                sb.Append( ch);
            }
            else {
                sb.Append( replacement);
            }
        }

        return sb.ToString();
    }

の文字数がpattern任意のサイズになる場合(一般的にはそうではないと思います)、それをソートして . のArray.BinarySearch()代わりにArray.indexOf().

このような単純な変換の場合、正規表現よりも高速であることにも問題はないと思います。

また、文字セットはpattern通常、文字列から取得される可能性が高いため (少なくとも、このタイプの API に関する私の一般的な経験では)、メソッドのシグネチャを次のようにしないのはなぜですか。

public static string ReplaceNot(this string original, string pattern, char replacement)

またはさらに良いことに、オーバーロードがあり、どこにまたは ?patternを指定できますchar[]string?

于 2009-05-05T19:11:07.363 に答える
2

StringBuilder には文字とカウントを受け取るオーバーロードがあるため、中間文字列を作成して StringBuilder に追加する必要はありません。これを置き換えることで約20%の改善が得られます:

sb.Append(new string(replacement, index - old - 1));

と:

sb.Append(replacement, index - old - 1);

この:

sb.Append(new string(replacement, original.Length - (old + 1)));

と:

sb.Append(replacement, original.Length - (old + 1));

(あなたが言ったコードをテストしたところ、約 4 倍高速でしたが、約 15 倍遅いことがわかりました...)

于 2009-05-05T19:56:23.230 に答える
0

O(n)になります。すべてのアルファベットと空白を に置き換えているようですが*、現在の文字がアルファベット/空白かどうかをテストして置き換えてみませんか?

于 2009-05-05T18:53:32.693 に答える