用于匹配开始/结束标记的Java正则表达式会导致堆栈溢出
Java
Pattern
类的标准实现使用递归来实现许多forms的正则表达式(例如,某些运算符,交替)。
这种方法导致堆栈溢出问题,输入字符串超过(相对较小)长度,甚至可能不超过1,000个字符,具体取决于所涉及的正则表达式。
一个典型的例子是以下正则表达式,使用交替从周围的XML字符串中提取可能的多行元素(名为Data
),该字符串已经提供:
(?(?:.|\r|\n)+?)
上面的正则表达式与Matcher.find()
方法一起用于读取“数据”捕获组并按预期工作,直到提供的输入字符串的长度超过1,200个字符左右,在这种情况下,它会导致堆栈溢出。
是否可以重写上述正则表达式以避免堆栈溢出问题?
关于堆栈溢出问题的原因的更多细节:
有时,正则表达式
Pattern
类将抛出StackOverflowError
。 这是已知错误#5050507的一种表现forms,自Java 1.4以来一直存在于java.util.regex
包中。 这个bug就在这里,因为它有“不会修复”的状态。 发生此错误是因为Pattern
类将正则表达式编译为一个小程序,然后执行该程序以查找匹配项。 此程序是递归使用的,有时当进行过多的递归调用时会发生此错误。 有关更多详细信息,请参阅错误说明。 它似乎主要是由交替使用引发的。
你的正则表达式(有替代)匹配两个标签之间的任何1+个字符。
您可以使用延迟点匹配模式与Pattern.DOTALL
修饰符(或等效的嵌入标志(?s)
)来制作.
匹配换行符号:
(?s)(?.+?)
看到这个正则表达式演示
但是,在大量输入的情况下,惰性点匹配模式仍会占用大量内存。 最好的方法是使用unroll-the-loop方法 :
(?[^<]*(?:<(?!/?Data>)[^<]*)*)
请参阅正则表达式演示
细节 :
-
– 文字文本
-
(?
– 捕获组“数据”的开始-
[^<]*
- 除<
以外的零个或多个字符 -
(?:<(?!/?Data>)[^<]*)*
- 0或更多序列:-
<(?!/?Data>)
- 一个<
未跟随Data>
或/Data>
-
[^<]*
- 除<
以外的零个或多个字符
-
-
-
)
- “数据”组的结束 -
- 关闭分隔符