我有一个方法来替换除我指定的字符之外的每个字符。例如,

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

有帮助吗?

解决方案

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

诀窍是初始化一个包含所有替换字符的新字符串,因为大多数字符都将被替换。

其他提示

你不能像这样使用Regex.Replace:

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

我不知道这是否会更快,但它可以避免新增字符串,因此可以将它们附加到字符串构建器,这可能有所帮助:

    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归因
不隶属于 StackOverflow
scroll top