繁体   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