Java正则表达式匹配开始/结束标签导致堆栈溢出

2023-12-22

标准执行情况Java Pattern类使用递归来实现多种形式的正则表达式(例如,某些运算符、交替)。

这种方法会导致输入字符串超过(相对较小)长度的堆栈溢出问题,该长度甚至可能不超过 1,000 个字符,具体取决于所涉及的正则表达式。

一个典型的示例是以下正则表达式,使用交替来提取可能的多行元素(名为Data) 来自已提供的周围 XML 字符串:

<Data>(?<data>(?:.|\r|\n)+?)</Data>

上面的正则表达式与Matcher.find()方法读取“数据”捕获组并按预期工作,直到提供的输入字符串的长度超过 1,200 个字符左右,在这种情况下会导致堆栈溢出。

可以重写上面的正则表达式来避免堆栈溢出问题吗?


有关的更多详细信息堆栈溢出问题的根源 http://www.javaworld.com/article/2077757/core-java/optimizing-regular-expressions-in-java.html?page=4:

有时正则表达式Pattern类将抛出一个StackOverflowError。这是一个体现已知错误#5050507 http://www.javaworld.com/article/2077757/core-java/optimizing-regular-expressions-in-java.html?page=4#resources,这已经在java.util.regex从 Java 1.4 开始打包。该错误会一直存在,因为它处于“无法修复”状态。出现此错误的原因是Pattern类将正则表达式编译成一个小程序,然后执行该程序以查找匹配项。该程序是递归使用的,有时当递归调用太多时会出现此错误。请参阅错误描述 http://www.javaworld.com/article/2077757/core-java/optimizing-regular-expressions-in-java.html?page=4#resources更多细节。看来它主要是通过使用交替来触发的。

您的正则表达式(具有交替)匹配两个标签之间的任何 1+ 个字符。

您可以使用惰性点匹配模式Pattern.DOTALL修饰符(或等效的嵌入标志(?s))这将使.也匹配换行符:

(?s)<Data>(?<data>.+?)</Data>

See 这个正则表达式演示 https://regex101.com/r/rY5mI2/1

然而,在输入巨大的情况下,惰性点匹配模式仍然会消耗大量内存。最好的方法是使用展开循环法 http://www.softec.lu/site/RegularExpressions/UnrollingTheLoop:

<Data>(?<data>[^<]*(?:<(?!/?Data>)[^<]*)*)</Data>

See the 正则表达式演示 https://regex101.com/r/oG5aE9/1

Details:

  • <Data>- 文字<Data>
  • (?<data> - start of the capturing group "data"
    • [^<]*- 零个或多个字符以外的字符<
    • (?:<(?!/?Data>)[^<]*)* - 0 or more sequences of:
      • <(?!/?Data>) - a <后面没有跟Data> or /Data>
      • [^<]*- 零个或多个字符以外的字符<
  • )- “数据”组的末尾
  • </Data>- 结束分隔符
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java正则表达式匹配开始/结束标签导致堆栈溢出 的相关文章

随机推荐