【问题标题】:"Exception in thread "main" java.lang.StackOverflowError"“线程“主”java.lang.StackOverflowError 中的异常”
【发布时间】:2014-05-08 07:18:06
【问题描述】:

我在使用正则表达式时收到“线程“主”java.lang.StackOverflowError 中的异常”:

(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)") 

对于一个长字符串。实际上,我想根据 .csv 文件中的 ','(在 .csv 文件中的 "" 之外)拆分字符串。它对 4​​50 列工作正常,但对更多列给出错误,如下所示---

Exception in thread "main" java.lang.StackOverflowError
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4148)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4556)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4683)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4615)
    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3715)
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4170)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3715)
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4170)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4556)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4683)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4615)
    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3715)
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4170)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3715)
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4170)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4556)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4683)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4615)
    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3715)
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4170)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3715)
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4170)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4556)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4683)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4615)
    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3715)
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4170)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3715)
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4170)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4556)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4683)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4615)
    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3715)
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4170)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3715)
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4170)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4556)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4683)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4615)
    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3715)
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4170)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3715)
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4170)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4556)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4683)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4615)
    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3715)
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4170)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3715)
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4170)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4556)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4683)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4615)
    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3715)
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4170)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3715)
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4170)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4556)

【问题讨论】:

  • 您可能是灾难性回溯的受害者。请参阅here 了解匹配“双引号、\”转义\“字符串”的好方法
  • 另外,既然这似乎是 CSV,为什么不使用 OpenCSV?
  • 很遗憾没有一个好的 CSV 库可用(据我所知)。这个问题源于人们应该如何解释 CSV 文件。首先,您可以指定分隔符',' 和引号字符'"'。引号字符围绕字段,例如"Hello, my", name, " is ", jared 将创建以下字段:{"Hello, my", "name", " is ", "jared"}。您可以遍历行的字符以生成这些字段(逐行、逐字符)。当引号字符需要成为字段的一部分时,它就会成为一个问题!

标签: java regex


【解决方案1】:

使用atomic group 代替您不需要的捕获组:

,(?=(?>[^\"]*\"[^\"]*\")*[^\"]*$)

这应该会加快速度并防止不必要的回溯。

【讨论】:

    【解决方案2】:

    我在通过正则表达式查找长字符串时遇到问题(当行长度超过 25k 个字符时)。我通过在我的正则表达式末尾添加加号 (+) 来修复它。

    参见所有格量词 https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html

    这是我修改后的正则表达式

    // find string using pattern `normal* (special normal*)*` 
    // where special — any escaped symbol
    Pattern stringRe = Pattern.compile("\"[^\\\\\"]*(\\\\.[^\\\\\"]*)*+\"");
    

    这是我遇到 StackOverflowError 时解析 json 的完整代码

    Pattern spaceRe = Pattern.compile("[\\s\\t\\n ]+");
    // THIS PATTERN IS SAFE FOR A LONG STRING
    // find string using pattern `normal* (special normal*)*` 
    // where special — any escaped symbol
    Pattern stringRe = Pattern.compile("\"[^\\\\\"]*(\\\\.[^\\\\\"]*)*+\"");
    Pattern numberRe = Pattern.compile("\\d+(?:.\\d+)?");
    Pattern boolRe = Pattern.compile("true|false");
    Pattern nilRe = Pattern.compile("null");
    Pattern openCurlyBraceRe = Pattern.compile("\\{");
    Pattern closeCurlyBraceRe = Pattern.compile("\\}");
    Pattern openSquareBracketRe = Pattern.compile("\\[");
    Pattern closeSquareBracketRe = Pattern.compile("\\]");
    Pattern colonRe = Pattern.compile(":");
    Pattern commaRe = Pattern.compile(",");
    Pattern re = Pattern.compile("(?:" + spaceRe +
            "|" + stringRe.pattern() +
            "|" + numberRe.pattern() +
            "|" + boolRe.pattern() +
            "|" + nilRe.pattern() +
            "|" + openCurlyBraceRe.pattern() +
            "|" + closeCurlyBraceRe.pattern() +
            "|" + openSquareBracketRe.pattern() +
            "|" + closeSquareBracketRe.pattern() +
            "|" + colonRe.pattern() +
            "|" + commaRe.pattern() + ")"
    );
    int i = 0;
    Matcher matcher = re.matcher(json);
    while (matcher.find()) {
       // some staff for parsing
    }
    

    关于https://regular-expressions.mobi/possessive.html?wlr=1的一些附加信息

    当占有量词很重要时

    所有格量词的主要实际好处是加快您的正则表达式。特别是,所有格量词让你的正则表达式失败得更快。在上面的例子中,当右引号不匹配时,我们知道正则表达式不可能跳过引号。所以没有必要回溯和检查报价。我们通过使量词所有格来使正则表达式引擎意识到这一点。事实上,有些引擎,包括 JGsoft 引擎,在编译你的正则表达式时会检测到 [^"]* 和 " 是互斥的,并自动将星号设为所有格。

    【讨论】:

      猜你喜欢
      • 2012-09-28
      • 1970-01-01
      • 1970-01-01
      • 2012-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-18
      • 1970-01-01
      相关资源
      最近更新 更多