意外的preg匹配行为与\ s和?

时间:2012-06-22 14:21:13

标签: php regex preg-match

这很简单,我不明白为什么以下内容匹配:

preg_match('/\<td valign="top" class="bericht"\>(.*\s)*<\/td>/',$html,$matches3);

这个不是:

preg_match('/\<td valign="top" class="bericht"\>(.*(\s)?)*<\/td>/',$html,$matches3);
我想?意味着零或一个。所以我不明白这怎么会让事情不匹配。

使用RegexPal(http://regexpal.com/)进行测试时,一切都按预期工作。所以第二个匹配。

2 个答案:

答案 0 :(得分:2)

除了Tim Pietzcker所说的话。 。

你如何确定第二个不匹配?请注意,虽然第一个模式将$matches3[1]设置为表格单元格的内容,但第二个模式将始终将$matches3[1]设置为空字符串。

假设$html看起来像这样:

<td valign="top" class="bericht">yes </td>

然后,第一个模式中的(.*\s)*将与yes 匹配,之后不再匹配,因此它会将yes 存储在$matches3[1]中。

但第二种模式中的(.*(\s)?)*将匹配yes ,然后是之后的空字符串,因此它会将空字符串存储在$matches3[1]中。

我不确定你要做什么,但如果你的目标只是捕捉<td valign="top" class="bericht"></td>之间的所有内容,无论那可能是什么,那么你应该写:

preg_match('/\<td valign="top" class="bericht"\>(.*?)<\/td>/s',$html,$matches3);

(其中*?表示“零次或多次,但最好尽可能少,/s表示”允许.匹配任何字符,甚至换行符“ )。

答案 1 :(得分:1)

这两者都应该匹配。但第二个可能会遇到catastrophic backtracking,因为

  • .也匹配\s(除了,这里是踢球者,换行符)
  • 它使用嵌套的无限量词(实质上,它是(.*)*,因为\s是可选的)

因此,如果输入足够大的输入和足够的换行符,PHP将在超过一定的回溯阈值后停止匹配(你可以在某处配置,但我忘了在哪里),而在线正则表达式测试器可以继续使用所有的可能的排列。