java正则表达式中的堆栈溢出

Posted

技术标签:

【中文标题】java正则表达式中的堆栈溢出【英文标题】:Stack Overflow in java regex 【发布时间】: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(***Error er) 
            System.out.println("Third try Block ***Error in regex pattern to reform the rtf tags................");
            er.printStackTrace();
        //  throw er;
     

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

java.lang.***Error
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 一点也不简单。 【参考方案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(***Error 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 过于苛刻。整个“我必须使用正则表达式”的心态在这个网站上是如此普遍,以至于有时让你想从山顶尖叫:“并非所有问题都必须用正则表达式解决!"

以上是关于java正则表达式中的堆栈溢出的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式全名验证

将 po box javascript 正则表达式转换为 c# 正则表达式

正则表达式 —— 回溯陷阱

正则表达式引发的惨案

如何检查字符串是不是与 Thymeleaf 中的正则表达式匹配?

正则表达式的隐藏陷阱,你都了解么?