簡體   English   中英

反向String.Replace - 更快的方式嗎?

[英]Inverse String.Replace - Faster way of doing it?

我有一個方法來替換除我指定的字符之外的每個字符。 例如,

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字符串添加了一個測試用例,運行時間為100K而不是1M,以查看每個字符串的大小。 唯一令人驚訝的是,正則表達式“比其他表達式更好”,但它沒有任何幫助,因為它開始時非常緩慢:

User            Short * 1M  Long * 100K     Scale
John            319             2125            6.66
Luke            360             2659            7.39
Guffa           409             2827            6.91
Mine            447             3372            7.54
DirkGently      1094            9134            8.35
Michael         1591            12785           8.04
Peter           21106           94386           4.47

更新:我為Peter的版本創建了一個靜態變量的正則表達式,並將其設置為RegexOptions.Compiled為公平:

User            Short * 1M      Long * 100K     Scale
Peter           8997            74715           8.30

粘貼到我的測試代碼的鏈接,如果錯誤請糾正我: http://pastebin.com/f64f260ee

你不能像這樣使用Regex.Replace:

Regex regex = new Regex(@"[^.;/\\]");
string s = regex.Replace("test. stop; or, not", "*");

好吧,在大約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();
}

訣竅是初始化一個包含所有替換字符的新字符串,因為大多數字符都將被替換。

我不知道這是否會更快,但它避免了新的字符串,因此可以將它們附加到字符串構建器,這可能會有所幫助:

    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

這是你的另一個版本。 我的測試表明它的性能非常好。

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

    for (int i = 0; i < buffer.Length; i++)
    {
        bool replace = true;

        for (int j = 0; j < pattern.Length; j++)
        {
            if (original[i] == pattern[j])
            {
                replace = false;
                break;
            }
        }

        buffer[i] = replace ? replacement : original[i];
    }

    return new string(buffer);
}

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

(我測試過你說的代碼大約快了四倍,我覺得它慢了大約15倍......)

它將是O(n)。 您似乎用*替換所有字母和空格,為什么不測試當前字符是否為字母/空格並替換它?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM