【问题标题】:Catastrophic backtracking issue with large string using regular expression使用正则表达式的大字符串的灾难性回溯问题
【发布时间】:2018-07-30 08:39:20
【问题描述】:

我正在尝试捕获两个字符串之间的所有内容,问题是我要捕获的这个字符串可以长达 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 <.>

注意中间可以有一千行数字、点和逗号

【问题讨论】:

  • 这些点是不是应该出现在标签中(即&lt;.CSVIntervalData&gt; / &lt;./CSVIntervalData&gt;)?
  • \s\S == .,不是吗? (如果您的正则表达式风格不包含带有 . 的换行符,则添加相应的修饰符。)
  • 请在标签中指定您使用的语言/工具
  • 几个问题:您的样品标签中有点,是错字吗?您在什么环境中运行正则表达式?您能否提供一个重现错误的示例(通过 regex101、ideone 或 pastebin 链接)?

标签: regex


【解决方案1】:

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

你可以做的是解开惰性模式:

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

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

[\s\S]*? 被替换为 [^&lt;]*(?:&lt;(?!/CSVIntervalData&gt;)[^&lt;]*)*:除 &lt; 之外的 0+ 个字符,然后是 &lt; 的任何 0+ 序列,而不是 /CSVIntervalData&gt;,然后是除 &lt; 之外的任何 0+ 字符。虽然它更长,但它匹配块中的文本,并且在预期匹配很长的情况下更快更可靠。如果您的文本在分隔符之间包含太多连续的&lt; 字符,则速度不会那么快,但实际数据通常不是这种情况。

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

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

this regex demo

【讨论】:

  • 我认为 OP 不想捕获结束标签。
  • @Jorge.V 对,这就是我的模式没有捕获组的原因。
  • 我的意思是,引用 OP:“我正在尝试捕获两个字符串之间的所有内容”,+ 他在他的示例中没有捕获组,我认为他正在寻找匹配之间的任何内容标签。不过令人困惑的问题。
  • @Jorge.V 好的,我在捕获组中添加了一个变体。
  • ++ 希望对 OP 有所帮助。
猜你喜欢
  • 2016-03-24
  • 2018-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-19
  • 2017-09-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多