大字符串在使用正则表达式时出现灾难性回溯问题

3
我将尝试捕获两个字符串之间的所有内容。问题是,我想要捕获的这个字符串可能长达3000行数字和逗号。因此,当这种情况发生时,我会遇到灾难性回溯错误。
以下是我使用的正则表达式和示例数据:
NEM12[\s\S]+?<\/CSVIntervalData>

<.CSVIntervalData>100,NEM12,2018年7月29日9:00,WBAYM,EEQ 200,3030910307,B1E1K1Q1,03,B1,N1,91111580千瓦时,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,,,2018年7月29日0点3分20秒, 900 <./CSVIntervalData>

请注意,中间可能会有数千行数字、小数点和逗号。


这些点是用来标记的吗(例如 <.CSVIntervalData> / <./CSVIntervalData>)? - James Whiteley
\s\S == .,对吗?(如果您的正则表达式不包括换行符与.,则添加相应的修饰符。) - CBroe
请在标签中指定您正在使用的编程语言/工具。 - Vadim Kotov
几个问题:您的示例标签中有点,这是打字错误吗?您在哪个环境中运行正则表达式?您能否提供一个样本(通过regex101、ideone或pastebin链接),以重现错误? - Aaron
1个回答

6

你的正则表达式是基于懒惰匹配模式的,这意味着如果需要匹配的字符串非常长,正则表达式引擎将会有很多开销。当匹配到NEM12时,会尝试匹配</CSVIntervalData>,一旦找不到,它就会扩展[\s\S]*?模式,匹配任何字符,然后再次测试</CSVIntervalData>模式,如此循环。一旦重复多次,你可能会遇到问题(在regex101上,你通常会看到超时问题,而不是灾难性回溯,因为这里没有回溯,只有贪婪模式才会触发回溯)。

你可以尝试去除懒惰模式:

NEM12[^<]*(?:<(?!/CSVIntervalData>)[^<]*)*</CSVIntervalData>

请查看正则表达式演示(注意317与46步骤的差异)。

[\s\S]*?被替换为 [^<]*(?:<(?!/CSVIntervalData>)[^<]*)*:0个以上的除<以外的任意字符,然后是0个以上的<序列,这些序列没有跟随/CSVIntervalData>,然后是0个以上的除<以外的任意字符。虽然更长,但它会按块匹配文本,并且在期望匹配较长的情况下更快、更可靠。如果您的文本在分隔符之间包含太多连续的<字符,它将不会那么快,但实际数据通常不是这种情况。

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

NEM12([^<]*(?:<(?!/CSVIntervalData>)[^<]*)*)</CSVIntervalData>
     ^                                     ^    

查看 这个正则表达式演示


我认为原帖作者不想捕获闭合标签。 - Jorge.V
@Jorge.V 没错,这就是为什么我的模式没有捕获组的原因。 - Wiktor Stribiżew
我的意思是,引用原帖:“我正在尝试捕获两个字符串之间的所有内容”,加上他在示例中没有捕获组,我认为他想匹配标签之间的任何内容。虽然问题有点混乱。 - Jorge.V
@Jorge.V 好的,我加了一个带捕获组的变量。 - Wiktor Stribiżew
希望这对楼主有所帮助。 - Jorge.V

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接