当前位置: 首页 > 面试题库 >

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

宰父单弓
2023-03-14
问题内容

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

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

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

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

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

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


问题答案:

有关堆栈溢出问题起源的更多详细信息:

有时regex
Pattern类会抛出StackOverflowError。这是已知错误#5050507的体现,该错误java.util.regex自Java 1.4
起已包含在软件包中。该错误将保留,因为它具有“无法修复”状态。发生此错误的原因是Pattern该类将正则表达式编译为一个小程序,然后执行该小程序以查找匹配项。该程序以递归方式使用,并且有时在进行过多的递归调用时会发生此错误。有关更多详细信息,请参见错误说明。
看来它主要是由使用交替触发的。


您的正则表达式(具有交替项)与两个标签之间的任意1个以上的字符匹配。

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

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

观看此正则表达式演示

但是,在输入量巨大的情况下,惰性点匹配模式仍会消耗大量内存。最好的解决方法是使用
展开循环方法

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

参见正则表达式演示

详细资料

  • <Data> -文字 <Data>
  • (?<data> -捕获组“数据”的开始
    • [^<]* -零个或多个其他字符 <
    • (?:<(?!/?Data>)[^<]*)* -0个或多个序列:
    • <(?!/?Data>)- <后面没有Data>或的/Data>
    • [^<]* -零个或多个其他字符 <
  • ) -“数据”组的结尾
  • </Data> -结束定界符


 类似资料:
  • 上面的正则表达式与方法一起使用,以读取“数据”捕获组,并按预期工作,直到提供的输入字符串长度超过1,200个字符左右,在这种情况下会导致堆栈溢出。 可以重写上面的正则表达式以避免堆栈溢出问题吗?

  • 我找不到堆栈溢出的来源,但似乎是外部的循环造成的。 提前道谢!

  • 问题内容: 我正在研究一个小的Python脚本来清理HTML文档。它的工作方式是接受KEEP的标签列表,然后解析不在列表中的HTML代码,破坏标签我一直在使用正则表达式来做到这一点,而且我已经能够匹配开始标签和自动关闭标签但不关闭标签。 我一直在尝试匹配结束标记的模式是。在我看来这是合乎逻辑的,所以为什么不起作用?本应匹配任何不是一个锚定标记(不就是“a”是可以anything –这只是一个例子)

  • 我正在将一些较旧的Boost regex代码转换为C++11的过程中,我在一个测试用例中偶然发现了一个问题。下面是一个使用std::regex导致堆栈溢出异常的场景,但使用boost::regex可以很好地工作。我没有更改正则表达式模式,并且已经验证了该模式是我想要的。似乎是这个特定的字符串输入片段导致了堆栈溢出。使用VS2012,x64调试生成:

  • 我正在使用一个正则表达式从任意长的输入字符串中提取键值对,并且遇到了这样的情况:对于具有重复模式的长字符串,它会导致堆栈溢出。 KV解析代码如下所示: 一些虚构的输出示例: 我显式地将generic放在上面,而不是在解析之前检查最大字符串长度的hacks(例如)。 我能想出的最粗俗的解决方法,一个真正的反模式,是 有趣的是,它在我试过的几次运行中都起作用了,但它不是一个值得推荐的有品位的东西。:-

  • 问题内容: 正则表达式可以匹配空格 或 字符串的开头吗? 我正在尝试用英镑符号替换缩写为GBP的货币。我可以匹配任何以GBP开头的东西,但我想更加保守一些,并在它周围寻找某些定界符。 我可以同时做后两个例子吗? 问题答案: 使用OR“ ”运算符: