【问题标题】:Why does this regular expression kill the Java regex engine?为什么这个正则表达式会杀死 Java 正则表达式引擎?
【发布时间】:2010-09-22 06:34:48
【问题描述】:

我有这个天真的正则表达式 "" (不包括引号)。好像是这样 直截了当,但当它与下面的 HTML 文本一起工作时,它确实是邪恶的。它将 Java 正则表达式引擎发送到无限循环。

我有另一个正则表达式(“<.>”),它做的事情有些相同,但它不会杀死任何东西。你知道为什么会这样吗?

<script language="JavaScript" type="text/javascript">
        var numDivs, layerName;
        layerName = "lnavLayer";
        catLinkName = "category";
        numDivs = 2;
        function toggleLayer(layerID){
            if (!(navigator.appName == "Netscape" && navigator.appVersion.substr(0, 1) < 5)){
                thisLayer = document.getElementById(layerName + layerID);
                categoryLink = document.getElementById(catLinkName + layerID);
                closeThem();
                if (thisLayer.className == 'subnavDefault'){
                    thisLayer.className = 'subnavToggled';
                    categoryLink.className = 'leftnavLinkSelectedSection';
                }
            }
        }
        function closeThem(){
            for(x = 0; x < numDivs; x++){
                theLayer = document.getElementById(layerName + (x
+ 1));
                thecategoryLink = document.getElementById(catLinkName + (x + 1));
                theLayer.className = 'subnavDefault';
                thecategoryLink.className = 'leftnavLink';
            }
        } var flag = 0; var lastClicked = 0
    //-->
    </script>

它甚至可以使用在线 Java 正则表达式工具(例如 www.fileformat.info/tool/regex.htm)或类似 RegexBuddy 的实用程序进行循环。

【问题讨论】:

    标签: java regex


    【解决方案1】:

    Java 正则表达式引擎崩溃的原因是您的正则表达式的这一部分导致堆栈溢出(确实!):

    [\s]|[^<]
    

    这里发生的是每个被\s匹配的字符也可以被[^

    A|B
    

    那么一个由三个空格组成的字符串可以匹配为 AAA、AAB、ABA、ABB、BAA、BAB、BBA 或 BBB。换句话说,这部分正则表达式的复杂度是 2^N。这将杀死任何对我所说的 catastrophic backtracking 没有任何保护措施的正则表达式引擎。

    在正则表达式中使用交替(竖线)时,请始终确保备选方案是互斥的。也就是说,最多允许一个备选方案匹配任何给定的文本位。

    【讨论】:

    • 无限循环的好解释
    • 这个答案表明它实际上不是一个无限循环,只是一个以指数时间运行的循环。
    • 一周后我回来了,发现了这个很好的答案。谢谢
    【解决方案2】:

    简单的正则表达式([\s]|[^&lt;]) 表示任何单个字符是空格或不是&lt; 字符,这是多余的,因为空格字符不是&lt; 字符。在我看来,您的真正意思是:

    `"<([^<])+?>"`
    

    我不确定这是否会解决无限循环,但我想我会指出这一点。

    【讨论】:

    • "&lt;([^&lt;&gt;])+&gt;" 会更好。那时你就不需要最小匹配了。
    【解决方案3】:

    另一个问题(除了 Jan 所说的)是你在括号内一次匹配一个字符,相当于这个简化的例子:

    (.)+
    

    每次执行这部分正则表达式时,正则表达式引擎都必须保存括号内的子表达式匹配的任何内容的开始和结束位置,以防它需要回溯。即使它是非捕获组也是如此,即,

    (?:.)+
    

    ...但是因为它是一个捕获组,所以必须保存更多信息。一次为一个角色经历所有这些变得非常昂贵。将带括号的组内的单个字符与组上的 *+ 量词匹配几乎永远不会正确。此外,您应该仅在需要捕获某些内容时使用捕获组;否则,请使用非捕获品种。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-29
      • 2020-03-22
      • 2013-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-24
      • 1970-01-01
      相关资源
      最近更新 更多