我有两个文本框,一个用于输入,另一个用于输出。我需要从输入中仅过滤十六进制字符并以大写形式输出。我已经检查过使用正则表达式(Regex
)比使用循环要快得多。
我当前的代码首先是大写,然后过滤十六进制数字,如下所示:
string strOut = Regex.Replace(inputTextBox.Text.ToUpper(), "[^0-9^A-F]", "");
outputTextBox.Text = strOut;
另外:
string strOut = Regex.Replace(inputTextBox.Text, "[^0-9^A-F^a-f]", "");
outputTextBox.Text = strOut.ToUpper();
输入最多可包含32k个字符,因此速度非常重要。我使用TimeSpan
来衡量但结果并不一致。
我的问题是:哪些代码具有更好的速度性能以及为什么?
答案 0 :(得分:3)
这绝对是一个过早优化的例子:32K字符对于在现代计算机上运行的精细调整的正则表达式引擎来说并不是什么大问题,所以这个优化任务主要是理论上的。
在讨论性能之前,值得指出的是表达式可能没有按照你想要的那样做,因为它们允许^
个字符进入输出。您需要改为使用[^0-9A-F]
和[^0-9A-Fa-f]
。
两个正则表达式的速度是相同的,因为字符类中的字符数几乎没有区别。但是,将在可能更短的字符串上调用第二个组合ToUpper
调用,因为将删除所有无效字符。因此,第二种选择可能稍快一些。
但是,如果必须将其优化到最后一个CPU周期,则可以在没有正则表达式的情况下重写它,以避免在ToUpper
中分配内存:遍历循环中的输入字符串,并添加所有有效字符到你去StringBuilder
。当您看到小写字符时,将其转换为大写。
答案 1 :(得分:1)
测试很简单:
using System;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string letters = "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ";
Random random = new Random();
string[] strings = Enumerable.Range(0, 5000).Select(i1 => string.Join("", Enumerable.Range(0,32000).Select(i2 => letters[random.Next(0, letters.Length - 1)]))).ToArray();
Stopwatch stopwatchA = new Stopwatch();
stopwatchA.Start();
foreach (string s in strings)
Regex.Replace(s.ToUpper(), "[^0-9^A-F]", "");
stopwatchA.Stop();
Stopwatch stopwatchB = new Stopwatch();
stopwatchB.Start();
foreach (string s in strings)
Regex.Replace(s, "[^0-9^A-F^a-f]", "").ToUpper();
stopwatchB.Stop();
Debug.WriteLine("stopwatchA: {0}", stopwatchA.Elapsed);
Debug.WriteLine("stopwatchB: {0}", stopwatchB.Elapsed);
}
}
}
运行1:
秒表A:00:00:39.6552012
秒表B:00:00:40.6757048
运行2:
秒表A:00:00:39.7022437
秒表B:00:00:41.3477625
在那些跑步中,第一种方法更快。
答案 2 :(得分:0)
在理论大小上,string.ToUpper()
可能会分配一个新字符串(请记住,.NET字符串在语义上是不可变的),但另一方面,正则表达式可以节省内存,即在一般情况下它应该更快(对于大字符串)。如果使用toUpper()
调用,输入字符串也会循环两次。