Regex.match中的C#性能问题

时间:2011-02-18 09:19:04

标签: c# regex

大家好 我在C#中使用Regex.match来逐行逐步调整文本文件。我发现当线条与模式不匹配时会花费更多时间(约2-4秒)。但是比赛时花费的时间少于1秒。谁能告诉我如何改善表现?

这是我正在使用的正则表达式:

^.*?\t.*?\t(?<npk>\d+)\t(?<bol>\w+)\t.*?\t.*?\t.*?\t.*?\t.*?\t.*?\t.*?\t.*?\t.*?\t\s*(?<netValue>[\d\.,]+)\t.*?\t.*?\t(?<item>\d{6})\t(?<salesDoc>\d+)\t(?<acGiDate>[\d\.]{10})\t.*?\t.*?\t.*?\t.*?\t.*?\t(?<delivery>\d+)\t\s*(?<billQuantity>\d+)\t.*?\t(?<material>[\w\-]+)\tIV$

2 个答案:

答案 0 :(得分:7)

仅在正则表达式无法匹配时才会显示的性能问题通常归因于catastrophic backtracking。当正则表达式允许许多可能的组合匹配主题文本时,会发生这种情况,所有这些必须由正则表达式引擎尝试,直到它可能声明失败。

在您的情况下,失败的原因是显而易见的:

首先,你所做的事情不应该用正则表达式来完成,而应该使用CSV解析器(或者你的情况下是TSV解析器)。

如果你坚持使用正则表达式,你仍然需要改变一些东西。你的问题是分隔符\t也可以用点(.)匹配,所以除非整个字符串匹配,否则正则表达式引擎必须尝试排列,如上所述。

因此,向前迈出的一大步是将所有.*?更改为适用的[^\t]*,并使用{m,n}运算符压缩重复:

^(?:[^\t]*\t){2}(?<npk>\d+)\t(?<bol>\w+)(?:\t[^\t]*){9}\t\s*(?<netValue>[\d\.,]+)(?:\t[^\t]*){2}\t(?<item>\d{6})\t(?<salesDoc>\d+)\t(?<acGiDate>[\d\.]{10})(?:\t[^\t]*){5}\t(?<delivery>\d+)\t\s*(?<billQuantity>\d+)\t[^\t]*\t(?<material>[\w\-]+)\tIV$

我希望我没有错误记录:)


仅供参考:

匹配此文字

1   2   3   4   5   6   7   8   9   0

以上正则表达式摘录

.*?\t.*?\t.*?\t.*?\t.*?\t.*?\t.*?\t.*?\t.*?\t\s*(?<netValue>[\d\.,]+)

采用正则表达式引擎39步。

当你提供这个文本时,不过:

1   2   3   4   5   6   7   8   9   X

需要使用正则表达式引擎 4602 来确定它无法匹配。

如果您使用

(?:[^\t]*\t){9}\s*(?<netValue>[\d\.,]+)
相反,引擎需要30个步骤才能成功匹配,只有39个步骤才能尝试失败。

答案 1 :(得分:4)

预编译通常会有所帮助:

private static readonly Regex re = new Regex(pattern, RegexOptions.Compiled);

然而,我想知道在这个特定情况下它是否与正则表达式相关 - 可能是一些昂贵的反向引用。正则表达式不是总是要使用的工具,例如......


现在编辑,这似乎是分隔数据:

分隔数据可以更有效地使用解析方法,而不是正则表达式。您可能甚至可以使用var parts=line.Split('\t')(并按索引访问parts),但如果失败 - 此csv reader可以选择控制分隔符等。