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

Ali*_*Ali 35 java regex stack-overflow

这是我的正则表达式

((?:(?:'[^']*')|[^;])*)[;]
Run Code Online (Sandbox Code Playgroud)

它用分号标记一个字符串.例如,

Hello world; I am having a problem; using regex;
Run Code Online (Sandbox Code Playgroud)

结果是三个字符串

Hello world
I am having a problem
using regex
Run Code Online (Sandbox Code Playgroud)

但是当我使用大输入字符串时,我得到了这个错误

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)
Run Code Online (Sandbox Code Playgroud)

这是怎么造成的,我该如何解决?

Jee*_*tra 53

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

一个可能的解决方案是重写你的正则表达式不使用repititive选择,但如果你的目标是来标记上分号的字符串,你并不需要一个复杂的正则表达式所有真的,只是用String.split()用一个简单";"的争论.

  • @NullUserException 至少不是 JavaScript。我正在对包含 1600 多个字符的字符串执行相同的操作。它给了我 Java 中的 StackOverflowError 。然而 JavaScript 在 1 毫秒内就给出了正确的结果。老实说,我真的很震惊,在这个简单的任务中,编译语言及其所有可能的优化在性能方面可能比解释语言表现得更差。你可以自己尝试一下(F12中的浏览器控制台): `function test(str){console.time("test");console.log(/^([^']|'[^']*')*' [^']*$/.test(str));console.timeEnd("test")}` 然后 `test("1000+ char string")` (3认同)
  • 大多数正则表达式引擎都会遇到这个问题. (2认同)
  • 有关进一步参考,请访问http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6337993 (2认同)

And*_*rew 15

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


Rol*_*lig 7

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

是不是还有一些结构说"如果正则表达式与此点相匹配,不回溯"?也许这也派上用场了.(更新:称为占有量词).

一种完全不同的替代方法是编写一个名为的实用程序方法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.
Run Code Online (Sandbox Code Playgroud)