使用RegEx来解析大字符串时的java.lang.StackOverflowError

时间:2011-09-22 05:26:51

标签: java regex stack-overflow

这是我的正则表达式

((?:(?:'[^']*')|[^;])*)[;]

它以分号标记字符串。例如,

Hello world; I am having a problem; using regex;

结果是三个字符串

Hello world
I am having a problem
using regex

但是当我使用大输入字符串时,我收到此错误

Exception in thread "main" java.lang.StackOverflowError
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4168)
at java.util.regex.Pattern$Loop.match(Pattern.java:4295)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4227)
at java.util.regex.Pattern$BranchConn.match(Pattern.java:4078)
at java.util.regex.Pattern$CharProperty.match(Pattern.java:3345)
at java.util.regex.Pattern$Branch.match(Pattern.java:4114)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4168)
at java.util.regex.Pattern$Loop.match(Pattern.java:4295)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4227)

这是如何引起的?如何解决?

3 个答案:

答案 0 :(得分:51)

不幸的是,Java的内置正则表达式支持包含重复备用路径(即(A|B)*)的正则表达式存在问题。这被编译成递归调用,当在非常大的字符串上使用时会导致StackOverflow错误。

一种可能的解决方案是重写你的正则表达式而不使用重复替代,但如果你的目标是用分号标记字符串,你根本不需要复杂的正则表达式,只需使用String.split()一个简单的";"作为参数。

答案 1 :(得分:14)

如果你确实需要使用溢出堆栈的正则表达式,可以通过将类似-Xss40m的内容传递给JVM来增加堆栈的大小。

答案 2 :(得分:6)

+之后添加[^;]可能会有所帮助,这样您就可以减少重复次数。

是不是还有一些构造说“如果正则表达式与此点匹配,那么不回溯”?也许这也派上用场了。 (更新:称为possessive quantifiers)。

完全不同的替代方法是编写一个名为splitQuoted(char quote, char separator, CharSequence s)的实用程序方法,该方法显式迭代字符串并记住它是否看到过奇数引号。在该方法中,您还可以处理引号字符出现在带引号的字符串中时可能需要非转义的情况。

'I'm what I am', said the fox; and he disappeared.
'I\'m what I am', said the fox; and he disappeared.
'I''m what I am', said the fox; and he disappeared.