【发布时间】:2013-10-12 19:21:05
【问题描述】:
在构建一个简单的 regex 时,我发现它的 performance 配置文件很奇怪,而输入大小却增加了。
这是另一个具有类似行为的非常基本的正则表达式:
a+b
我用一个简单的基准对其进行了分析:
Regex regex = new Regex("a+b", RegexOptions.Compiled);
const int maxInputSize = 100;
const int n = 1000;
string input = "";
Stopwatch stopwatch = new Stopwatch();
for (int inputSize = 1; inputSize <= maxInputSize; ++inputSize)
{
input += 'a';
stopwatch.Restart();
for (int i = 0; i < n; ++i)
{
regex.Match(input);
}
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed.Ticks);
}
它在字符串“a”、“aa”、“aaa”...上运行正则表达式,并测量每个字符串长度进行 n 次匹配所花费的时间。
我知道回溯问题(例如,如果正则表达式类似于(a+a+)+b),但在这种情况下,即使考虑回溯,我也预计会有线性复杂性 .
例如,如果我们想匹配 n 次 'a',这是我天真地期望的工作流程:
take first 'a'
take second 'a'
...
take last 'a'
ooops nothing more to take => backtracking
release one 'a' and try to match 'b', nothing => backtracking
...
release second 'a' and retry to match 'b', nothing => backtracking
release first 'a'
ooops we're back at the beginning => no match
所以它应该执行类似 2n 的操作。
(该文档似乎证实了复杂性应该是线性的:http://msdn.microsoft.com/en-us/library/dsy130b4.aspx)
但相反,我观察到 二次复杂度:
所以我的问题是:
- 1) 我对线性复杂度的期望是否不合理?
- 2) 如果是,我在正则表达式匹配方面缺少什么?
- 3) 如果没有,我的基准测试是否存在缺陷?为什么?
- 4) 如果我的预期和基准是正确的,可能会出现什么问题?
提前感谢您的任何意见。
【问题讨论】:
-
您可能希望增加以秒为单位的样本量,而不是 100 个滴答声,因为您的时间提供者可能不像您预期的那样准确。
-
@DarrenKopp:说得好,但在这种情况下,样本量与实验一致:它需要十分之一毫秒,即使样本量更大,我也会得到相同的行为。谢谢。
-
实际上在这个链接中你指出有很多关于如何优化正则表达式和避免回溯等的建议。我认为在某些情况下需要更复杂的语法docs.microsoft.com/en-us/dotnet/standard/base-types/…
标签: c# .net regex time-complexity backtracking