【问题标题】:Stack Overflow in java regexjava正则表达式中的堆栈溢出
【发布时间】:2013-08-09 23:45:48
【问题描述】:

我是java新手。我在正则表达式 strHindiText 中收到 java Stack overflow 异常。 我该怎么做?

try {
     // This regex convert the pattern "{\fldrslt {\fcs1 \ab\af24 \fcs0 ऩ}{"
     // into "{\fldrslt {\fcs1 \ab\af24 \fcs0 ऩ}}}{"
     // strHindiText = strHindiText.replaceAll("\\{(\\\\fldrslt[ ])\\{((\\\\\\S+[ ])+)((\\s*&#\\d+;\\s*(-|,|/|\\(|\\)|\"|;|\\.|'|<|>|:|\\?)*)+)\\}\\{","{$1{$2$4}}}{");

     // This regex convert the pattern "{\fcs0 \af0 &#2345;{ or {\fcs0 \af0 *\tab &#2345;{" 
     // into "{\fcs0 \af0 &#2345; }{"
     strHindiText = strHindiText.replaceAll("\\{\\s*((\\\\\\S+[ ](\\*)?)+\\s*)(-|,|/|\\(|\\)|\"|;|\\.|'|<|>|:|\\?)*[ ]*(((&#\\d+;)[ ]*(-|,|/|\\(|\\)|\"|;|\\.|'|<|>|:|\\?)*[ ]*)+)\\{", "{$1 $4$5 }{");

     // This regex convert the pattern "{&#2345; \fcs0 \af0 {" 
     // into "{&#2345; \fcs0 \af0 }{"
     strHindiText = strHindiText.replaceAll("\\{\\s*(((&#\\d+;)[ ]*(-|,|/|\\(|\\)|\"|;|\\.|'|<|>|:|\\?)*[ ]*)+)[ ]*((\\\\\\S+[ ])+)\\{", "{$1 $5 }{");

     } catch(StackOverflowError er) {
            System.out.println("Third try Block StackOverflowError in regex pattern to reform the rtf tags................");
            er.printStackTrace();
        //  throw er;
     }



每当这些 strHindiText 包含大数据时,它都会给出 java stackoverflow 异常:

java.lang.StackOverflowError
2013-08-08 15:35:07,743 ERROR [STDERR] (http-127.0.0.1-80-9)    at java.util.regex.Pattern$Curly.match0(Pattern.java:3754)
2013-08-08 15:35:07,743 ERROR [STDERR] (http-127.0.0.1-80-9)    at java.util.regex.Pattern$Curly.match(Pattern.java:3744)
2013-08-08 15:35:07,744 ERROR [STDERR] (http-127.0.0.1-80-9)    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4227)
2013-08-08 15:35:07,744 ERROR [STDERR] (http-127.0.0.1-80-9)    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3366)
2013-08-08 15:35:07,745 ERROR [STDERR] (http-127.0.0.1-80-9)    at java.util.regex.Pattern$Curly.match0(Pattern.java:3782)
2013-08-08 15:35:07,745 ERROR [STDERR] (http-127.0.0.1-80-9)    at java.util.regex.Pattern$Curly.match(Pattern.java:3744)



我的 strHindiText 数据是:

 `{\rtlch\fcs1 \af1\afs18 \ltrch\fcs0 \f1\fs18\cf21\insrsid13505584 &#2349;&#2379;&#2346;&#2366;&#2354;&#32; &#2404; \par }\pard\plain \ltrpar\s16\ql \li0\ri0\sb100\sa100\sbauto1\saauto1\sl240\slmult0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid13505584 \cbpat20 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af1\afs18 \ltrch\fcs0 \cs21\b\f1\fs18\cf21\insrsid13505584 &#2309;&#2344;&#2381;&#2357;&#2375;&#2359;&#2339;&#32;&#2325;&#2352;&#2375;&#2306;&#32; :}{\rtlch\fcs1 \af1\afs18 \ltrch\fcs0 \f1\fs18\cf21\insrsid13505584  \par &#2349;&#2379;&#2346;&#2366;&#2354;&#32;&#44;&#32;&#2350;&#2343;&#2381;&#2351;&#32;&#2346;&#2381;&#2352;&#2342;&#2375;&#2358;&#32;&#2325;&#2368;&#32;&#2352;&#2366;&#2332;&#2343;&#2366;&#2344;&#2368;&#32;&#2346;&#2381;&#2352;&#2366;&#2325;&#2371;&#2340;&#2367;&#2325;&#32;&#2360;&#2369;&#2306;&#2342`

【问题讨论】:

  • 您的替代路径| 可能会导致递归调用,从而导致堆栈溢出。正则表达式的东西通常很复杂,而且你的正则表达式很大。我并不感到惊讶。
  • 我建议不要使用替代符号(例如a|b|c)来使用替代符号:[abc],这应该使正则表达式更清晰,您只需要转义右括号而不是其他字符.此外,您似乎想要做一些正则表达式不适合的事情 - 解析 - 对于不是文本但具有更高顺序的东西。
  • 你真的不应该使用 RegEx 进行如此庞大的解析。它的性能不是很好,因为每次你尝试匹配一个字符串时,正则表达式都会编译。
  • 您的代码的一切都是询问的问题。尝试将问题分解为多个小问题,而不是尝试使用巨大的正则表达式一次完成大量事情。根据您使用的正则表达式,如果您没有遇到内存问题,我会感到惊讶。
  • 我个人建议为您的 RTF 编写解析器,而不是尝试使用正则表达式对其进行拆分。正则表达式适用于简单的事情,我认为印地语中的 RTF 一点也不简单。

标签: java regex stack-overflow


【解决方案1】:

这不是一个完整的答案,仅供您参考。

在你的正则表达式中:

(-|,|/|\\(|\\)|\"|;|\\.|'|&lt;|&gt;|:|\\?)*可以写成[-,/()\";.'&lt;&gt;:?]*

由于这种模式出现了两次(在您的第一个正则表达式中),这会立即将您的正则表达式缩短 40 个字符,并使这些部分更具可读性。

【讨论】:

    【解决方案2】:

    选项 1 - 治疗症状

    在您的正则表达式中查找递归调用。

    如果您不确定问题出在哪里:请尝试a regex tester like this

    选项 2 - 治疗原因(更好)

    如果有更好的工具来完成您的任务,请不要使用正则表达式

    在您的情况下,您可以:搜索 RTF 解析库或编写自己的解析器。
    例如就像 jahroy 在 cmets 中指出的 here

    【讨论】:

      【解决方案3】:

      试试这个来捕捉错误

      public class Example {
          public static void endless() {
              endless();
          }
      
          public static void main(String args[]) {
              try {
                  endless();
              } catch(StackOverflowError t) {
                  // more general: catch(Error t)
                  // anything: catch(Throwable t)
                  System.out.println("Caught "+t);
                  t.printStackTrace();
              }
              System.out.println("After the error...");
          }
      }
      

      更重要的是尝试增加堆栈的大小,将其添加到您的正则表达式中

      +'xss='xss
      

      添加“+”符号会更改运算符以防止回溯,因为在您的情况下这似乎不是必需的。

      【讨论】:

      • 他应该考虑使用正确的工具来完成工作,而不是治疗使用错误工具所导致的症状......
      • 可能溢出来自递归问题而不是正则表达式的贪婪。通过使运算符具有所有格性,我们可以消除分支和递归处理,从而使该表达式更高效并减少内存使用。
      • 我要么找一个 RTF 解析库,要么自己写一个。如果我自己写一个,我会将解析分解为小任务,而不是尝试一次完成所有事情。如果我不得不使用正则表达式,我会让它们保持小而简单,并确保它们只对小段文本进行操作。我永远不会考虑将整个文档提供给单个复杂的正则表达式。
      • 谷歌搜索大约需要 5 秒才能找到 this(也许会有所帮助,也许不会……)
      • 好的。对不起,如果我的 cmets 过于苛刻。整个“我必须使用正则表达式”的心态在这个网站上是如此普遍,以至于有时让你想从山顶尖叫:“并非所有问题都必须用正则表达式解决!"
      猜你喜欢
      • 2013-07-05
      • 2013-03-19
      • 2016-10-07
      • 2019-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-17
      相关资源
      最近更新 更多