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