大字符串使用正则表达式的灾难性回溯问题

时间:2018-07-30 08:39:21

标签: regex

我正在尝试捕获两个字符串之间的所有内容,问题是我要捕获的字符串可以长到3000行数字和逗号。因此,当发生这种情况时,我会遇到灾难性的回溯错误。

这是我正在使用的正则表达式,也是下面的示例数据

NEM12[\s\S]+?<\/CSVIntervalData>
  

<。CSVIntervalData> 100,NEM12,201807290900,WBAYM,EEQ   200,3030910307,B1E1K1Q1,03,B1,N1,91111580,kWh,30,   300,20180728,.278,.278,.278,.278,.278,.278,.278,.278,.278,.278,.278,.278,.278,.056,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,.074,.278,.278,.278,.278 ,.278,.278,.278,.278,.278,.278,.278,.278,.278,E75 ,,, 20180729000320,   900   <./ CSVIntervalData>

请注意,之间可以包含一千行数字,点和逗号

1 个答案:

答案 0 :(得分:6)

Your regex基于惰性匹配模式,如果您需要匹配的字符串很长,则这对正则表达式引擎意味着很多开销。当NEM12匹配时,将尝试</CSVIntervalData>,一旦引擎找不到它,它就会展开[\s\S]*?模式,匹配任何字符,然后再次测试{{1 }}模式,依此类推。多次执行后,可能会遇到问题(在regex101上,您通常会看到超时问题,而不是灾难性的回溯,因为这里没有 lazy 模式的回溯,回溯仅由贪婪模式触发)。

您可能要做的是解开惰性模式:

</CSVIntervalData>

请参见regex demo(请注意317与46步的区别)。

NEM12[^<]*(?:<(?!/CSVIntervalData>)[^<]*)*</CSVIntervalData> 替换为[\s\S]*?:除[^<]*(?:<(?!/CSVIntervalData>)[^<]*)*之外的0+个字符,然后<的任何0+序列不跟随< /CSVIntervalData>以外的任何0+个字符。尽管它更长一些,但它匹配大块文本,并且在预期匹配长的情况下更快,更可靠。如果文本在定界符之间包含太多连续的<字符,将不会那么快,但是对于真实数据通常不是这种情况。

如果您需要捕获<NEM12这两个字符串之间的内容,请不要忘记捕获组:

</CSVIntervalData>

请参见this regex demo