使用正则表达式模式时的灾难性回溯错误

时间:2015-11-10 07:49:42

标签: php regex backtracking

我的正则表达式是:

 (<span style="color:green">?(\s*|\w*|\S*)*<li>)(?! ?\s*<\/span>)

每当我尝试输入时:

 <span style="color:green"> anything <li> 

它工作正常,但每当最后一个条件发生时,只要li标签后面跟着结束的span标记,那么它就会出错: 我的输入是:

<span style="color:green"> anything <li></span> 

我的模式中的实际问题是什么? 而不是:(?!?\ s *&lt; / span&gt;)我也尝试过:

 ^(</span>)

但发生同样的错误。我将它嵌入PHP中。

简而言之,我需要做的是:每当li打开标签位于span开启标签之后,但是在li标签之后不存在跨度结束标签,那么我需要用某些东西替换我的li标签。

1 个答案:

答案 0 :(得分:1)

由于(...|\w*|\S*)*<,您的灾难性回溯发生了。拿"an item"。在位置0,正则表达式需要测试所有这些可能性

<
()<
(\w)<
(\w\w)<
(\w\w\w)
()<
(\S)<
(\S\S)<
(\S\S\S)
()()<
()(\w)<
()(\w\w)<
()(\w\w\w)
()()<
()(\S)<
()(\S\S)<
()(\S\S\S)
(\w)()<
(\w)(\w)<
(\w)(\w\w)
(\w)()<
(\w)(\S)<
(\w)(\S\S)
(\w\w)()<
(\w\w)(\w)
(\w\w)()<
(\w\w)(\S)
(\w\w\w)()
(\w\w\w)()
()()<
()(\w)<
()(\w\w)<
()(\w\w\w)
()()<
()(\S)<
()(\S\S)<
()(\S\S\S)
(\S)()<
(\S)(\w)<
(\S)(\w\w)
(\S)()<
(\S)(\S)<
(\S)(\S\S)
(\S\S)()<
(\S\)(\w)<
(\S\S)()<
(\S\S)(\S)
(\S\S\S)()
(\S\S\S)()
()()()<
()()(\w)<
()()(\w\w)<
()()(\w\w\w)
()()()<
()()(\S)<
()()(\S\S)<
()()(\S\S\S)
()(\w)()<
()(\w)(\w)<
()(\w)(\w\w)
()(\w)()<
()(\w)(\S)<
()(\w)(\S\S)
()(\w\w)()<
()(\w\w)(\w)
()(\w\w)()<
()(\w\w)(\S)
()(\w\w\w)()
()()()<
()()(\w)<
()()(\w\w)<
()()(\w\w\w)
()()()<
()()(\S)<
()()(\S\S)<
()()(\S\S\S)
()(\S)()<
()(\S)(\w)<
()(\S)(\w\w)
()(\S)()<
()(\S)(\S)<
()(\S)(\S\S)
()(\S\S)()<
()(\S\)(\w)<
()(\S\S)()<
()(\S\S)(\S)
()(\S\S\S)()
(\w)()()<
(\w)()(\w)<
(\w)()(\w\w)
(\w)()()<
(\w)()(\S)<
(\w)()(\S\S)
(\w)(\w)()<
(\w)(\w)(\w)
(\w)(\w)()<
(\w)(\w)(\S)
(\w)(\w\w)()
(\w)(\w\w)()
(\w)()()<
(\w)()(\w)<
(\w)()(\w\w)
(\w)()()<
(\w)()(\S)<
(\w)()(\S\S)
(\w)(\S)()<
(\w)(\S)(\w)
(\w)(\S)()<
(\w)(\S)(\S)
(\w)(\S\S)()
(\w)(\S)(\w)
(\w)(\S\S)()
(\w\w)()()<
(\w\w)()(\w)
(\w\w)()()<
(\w\w)()(\S)
(\w\w)(\w)()
(\w\w)(\w)()
(\w\w)()()<
(\w\w)()(\w)
(\w\w)()()<
(\w\w)()(\S)<
(\w\w)(\S)()
(\w\w)(\S)()
(\w\w\w)()()
(\S)()()<
(\S)()(\w)<
(\S)()(\w\w)
(\S)()()<
(\S)()(\S)<
(\S)()(\S\S)
(\S)(\w)()<
(\S)(\w)(\w)
(\S)(\w)()<
(\S)(\w)(\S)
(\S)(\w\w)()
(\S)(\w\w)()
(\S)()()<
(\S)()(\w)<
(\S)()(\w\w)
(\S)()()<
(\S)()(\S)<
(\S)()(\S\S)
(\S)(\S)()<
(\S)(\S)(\w)
(\S)(\S)()<
(\S)(\S)(\S)
(\S)(\S\S)()
(\S)(\S)(\w)
(\S)(\S\S)()
(\S\S)()()<
(\S\S)()(\w)
(\S\S)()()<
(\S\S)()(\S)
(\S\S)(\w)()
(\S\S)(\w)()
(\S\S)()()<
(\S\S)()(\w)
(\S\S)()()<
(\S\S)()(\S)
(\S\S)(\S)()
(\S\S)(\S)()
(\S\S\S)()()
...

以消除"an "作为可能的匹配。 (我可能搞砸了某个地方,但你得到漂移。)

另请注意,\s|\S.(换行除外)。但你真正想要的是#34;而不是标签的开头&#34;:[^<]*</li>。这样,要消除"an "作为候选者,正则表达式引擎只需要测试这些:

<
[^<]<
[^<][^<]<

(另外,对stribizhev的评论+1:使用HTML处理库来处理HTML。)