【问题标题】:java.lang.StackOverflowError while using a RegEx to Parse big stringsjava.lang.StackOverflowError 使用正则表达式解析大字符串
【发布时间】:2011-11-22 12:28:43
【问题描述】:

这是我的正则表达式

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

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

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)

这是怎么引起的,我该如何解决?

【问题讨论】:

  • 你解析的字符串有多大?
  • 这个问题已经很老了,但是我可以使用所有格量词(*+ 而不是*)来解决类似的问题,以避免回溯
  • 我也应该使用原子组 (?>..) 而不是组 (?:..) 来防止回溯

标签: java regex stack-overflow


【解决方案1】:

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

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

【讨论】:

  • 大多数正则表达式引擎都会有这个问题。
  • 我想我没有把我的案子说清楚,抱歉。字符串不只是在分号上进行标记,而是会同时在许多模式上进行标记,在分号上标记只是一种简单的情况。
  • @Ali 好吧,一般来说:尽量避免使用通配符。您也可以尝试使用 jregex 等替代正则表达式库,但我不确定这是否能解决问题...
  • @NullUserException 至少不是 JavaScript。我在一个有 1600+ 个字符的字符串上做同样的事情。它给了我 Java 中的 StackOverflowError 。然而 JavaScript 在 1 毫秒内给了我正确的结果。 Tbh 我真的很震惊,在这个简单的任务中,编译语言及其所有可能的优化在性能方面比解释语言表现得更差。您可以自己尝试(F12 中的浏览器控制台):function test(str){console.time("test");console.log(/^([^']|'[^']*')*'[^']*$/.test(str));console.timeEnd("test")} 然后test("1000+ char string")
【解决方案2】:

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

【讨论】:

  • 通过 Xss 属性增加堆栈大小会增加 OutOfMemoryError 的可能性。虽然它会解决当前的问题。而不是增加 Xss 参考最佳答案。
  • 帮助我解决了我在启动 eclipse 时看到的堆栈溢出错误。我看到的错误是无法为 org.robotframework.red.robotsuitefile_robot 创建内容描述器。内容类型已被禁用。 java.lang.StackOverflowError
【解决方案3】:

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

是否还有一些结构说“如果正则表达式匹配到这一点,则不要回溯”?也许这也能派上用场。 (更新:它被称为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.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 2019-12-10
    • 2010-11-22
    • 2011-10-14
    相关资源
    最近更新 更多