【发布时间】:2016-06-25 19:22:32
【问题描述】:
给定:base64 字符串
何时:Foo 被调用
然后:Foo 返回输入字符串,并用以下字符替换 ('A' => '_', 'B' => '-', 'C' => '+') 并尽快完成
我比较了几种算法以确定Foo 的哪个版本更快。结果指向普通的string.Replace,这非常令人惊讶。我原以为正则表达式会在编译时受到初步打击,但随后会迅速突破并超越 string.Replace,每次调用 Foo 都会创建三个字符串副本。
我想看看其他人是否可以证实这些发现或解释为什么获胜者的表现优于其他人。
我使用这些算法运行了Foo 100k 次,结果是TimeSpan,在完成执行后在调试版本中使用StopWatch 测量:
00:00:00.0500790 <=== string.Replace [1]
00:00:00.0699696 <=== StringBuilder.Append [2]
00:00:00.0988960 <=== StringBuilder.Replace [3]
00:00:00.7440135 <=== Regex [4]
[1]:
Foo(string input)
{
return input.Replace("A", "_").Replace("B", "-").Replace("C", "+");
}
[2]:
Foo(string input)
{
var sb = new StringBuilder(input.Length);
foreach (var x in input)
{
if (x == 'A')
{
sb.Append('_');
}
else if (x == 'B')
{
sb.Append('-');
}
else if (x == 'C')
{
sb.Append('+');
}
else
{
sb.Append(x);
}
}
return sb.ToString();
}
[3]:
Foo(string input)
{
return new StringBuilder(input, input.Length).Replace("A", "_").Replace("B", "-").Replace("C", "+").ToString()
}
[4]:
static readonly Regex charsRegex = new Regex(@"[ABC]", RegexOptions.Compiled);
Foo(string input)
{
charsRegex.Replace(input, delegate (Match m)
{
var value = m.Value;
if (value == "A")
{
return "_";
}
else if (value == "B")
{
return "-";
}
else if (value == "C")
{
return "+";
}
return value;
});
}
【问题讨论】:
-
请注意,您的正则表达式代码指定了 IgnoreCase,而其他解决方案则没有。你试过没有它的正则表达式吗?或者,不区分大小写地尝试其他方法(可能需要 x2 次调用)
-
是的,这实际上不应该存在。已编辑
-
那么时间是没有 IgnoreCase 的代码吗?您能否验证其他 sn-ps 是否与您计时的匹配?它可能会让人们猜错方向。
-
另外,这是在编译时使用还是不使用调试信息和优化?由于没有中间变量,我希望编译器会优化链式替换以使其到位。因此,当您返回一个新字符串时,它不一定会创建一个字符串、替换所有字符串、返回新字符串、替换所有另一个字符串......但只有 ILDump 可以告诉
-
StringBuilder 将比 string.Replace 如果您替换更多字符更快。此外,Visual Studio 2015 中新的 Roslyn 编译器可以比 JIT 编译更好地优化可执行文件。
标签: c# regex string replace stringbuilder