大家好 我在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$
答案 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可以选择控制分隔符等。