我实际上正在优化大字符串的正则表达式转换。正如一些对Regex.Replace的调用花费了大量时间我插入了条件调用 - 这就行了
if (str.IndexOf("abc", 0, StringComparison.CurrentCultureIgnoreCase) > 0)
str1 = Regex.Replace(str, "abc...", string.Empty, RegexOptions.IgnoreCase);
令我惊讶的是,结果并不令人信服。有时更好,有时不是。甚至更糟。所以我测量了不区分大小写的IndexOf(我也尝试过StringComparison.OrdinalIgnoreCase)的性能,发现它可能比Regex.Match慢,即这个测试:
if( Regex.Match(str,"abc", RegexOptions.IgnoreCase).Success )...
特别是对于不匹配的大字符串(ascii)字符串“abc”,我发现Regex.Match的速度提高了4倍。
即使这个程序比IndexOf更快:
string s1 = str.ToLower();
if( s1.IndexOf("abc") ) ...
有谁知道更好的解决方案?
答案 0 :(得分:0)
因为indexOf是O(n * m),其中RegEx将被设为O(n + m)(其中n =字符串长度,m =搜索字符串长度)。
如果您正在严格搜索子字符串,那么阅读字符串搜索算法至少要了解预期的速度(以http://en.wikipedia.org/wiki/Substring_search开头)会很有用。
注意:文化敏感性比较可能比Ordinal明显慢(取决于您的场景,您可能无法使用Ordinal版本)。
与任何表演问题一样,需要离开和衡量。在带有Regex.isMatch的indexOf中,明确的赢家是Regex。我之所料,indexOf的行为不应该执行搜索字符串的任何预编译,必须使用O(n + m)算法,而Regex必须使用更优化的实现。
尝试测量以下搜索 - 我得到差不多5倍的差异,支持Regex进行100K操作。
static void Main(string[] args)
{
var stringToSearch = "AAAAAAAAAAAAAAAAAAAAbAAAAAAAAAAAAAAAAAAAAAbb";
Regex regExp = new Regex(stringToSearch, RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
var sourceText = "AAAAAAAAAAAAAAAAAAAAbAAAAAAAAAAAAAAAAAAAAAbAAAAAAAAAAAAAAAAAAAAbAAAAAAAAAAAAAAAAAAAAAbAAAAAAAAAAAAAAAAAAAAbAAAAAAAAAAAAAAAAAAAAAbAAAAAAAAAAAAAAAAAAAAbAAAAAAAAAAAAAAAAAAAAAbb";
const int Iterations = 100000;
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < Iterations; i++)
{
regExp.IsMatch(sourceText);
}
watch.Stop();
Console.WriteLine("RegExp: {0} ms", watch.ElapsedMilliseconds);
watch = new Stopwatch();
watch.Start();
for (int i = 0; i < Iterations; i++)
{
sourceText.IndexOf(stringToSearch, StringComparison.OrdinalIgnoreCase);
}
watch.Stop();
Console.WriteLine("RegExp: {0} ms", watch.ElapsedMilliseconds);
Console.ReadLine();
}
答案 1 :(得分:0)
最后,我为匹配测试编写了自己的函数。这是:
private static bool HasAsciiSubstring(string str, string sub)
{
char[] ss = sub.ToCharArray();
// Similar stupid small optimizations bring 30% speeding-up.
int ss_len = ss.Length;
for (int j = 0; j < ss_len; ++j)
ss[j] = (char)((byte)ss[j] | 32);
byte ss0 = (byte)ss[0];
int len = str.Length - ss_len;
for (int i = 0; i < len; ++i)
{
if ((str[i] | 32) == ss0)
{
bool bOk = true;
for (int j = 1; j < ss_len; ++j)
{
if ((str[i + j] | 32) != ss[j])
{
bOk = false;
break;
}
}
if (bOk)
return true;
}
}
return false;
}
此方法在WP7平台上提供了最佳结果(针对选定的大字符串)。这是
我需要一个能够在WP7,MonoDroid / Touch和桌面上表现令人满意的代码。因此我编写了一个小型WPF应用程序来测试至少桌面:
我相对较新的C#/ .Net(仅2年经验),但在其他平台上编程了数十年(主要是C / C ++)。我必须说明这对我来说是一种令人震惊的经历: