regexp php出错

时间:2010-07-17 20:44:49

标签: php regex

此代码中存在错误,我找不到它。我需要什么缺少的角色?

preg_replace(/<(?!\/?(?:'.implode('|',$white).'))[^\s>]+(?:\s(?:(["''])(?:\\\1|[^\1])*?\1|[^>])*)?>/','',$html);

3 个答案:

答案 0 :(得分:4)

除了其他一些内容之外,您还缺少单引号:

preg_replace('/<(?!\/?(?:' . implode('|',$white) . '))[...
             ^
             here!

此外,由于该模式包含单引号,因此必须使用反斜杠进行转义。

或者您也可以使用heredoc syntax;这不需要在模式中转义任何引号,并且可以嵌入表达式以进行扩展。

$pattern = <<<EOD
/pattern{embeddedExpression}morePattern/
EOD;

... preg_replace($pattern, ...)

答案 1 :(得分:0)

帮自己一个忙,并使用DOM and XPath代替正则表达式将HTML解析为avoid problems

答案 2 :(得分:0)

嗯,这部分是错误的:

(["'])(?:\\\1|[^\1])*?\1

这应该匹配用单引号或双引号括起来的序列,可能包括反斜杠转义的引号。但它不起作用,因为反向引用在字符类中不起作用。 \1被视为八进制表示法中的数字1,因此[^\1]匹配除U+0001之外的任何字符。

如果它似乎在大部分时间都有效,那是因为不情愿的量词(*?)。 (?:\\\1|[^\1])*?中的第一个替代方法正确地使用了转义引用,但是它不情愿地匹配任何字符,直到它看到未转义的引号。它在形式良好的文本上工作正常,但是会额外引用并且它会变得混乱。

匹配“捕获的#1组以外的任何东西”的正确方法是(?:(?!\1).)* - 也就是说,一次消耗一个字符,但只有在先行确认它不是捕获的文本的第一个字符之后。但我认为你最好分别处理各种报价;这个正则表达式足够复杂。

'~<(?!/?+(?:'.implode('|',$white).')\b)[^\s>]++(?:\s++'.
'(?:[^\'">]++|"(?:[^"\\]++|\\")*+"|\'(?:[^\'\\]++|\\\')*+\')*+)?+>~'

请注意在白名单更改后添加\b(字边界)。如果没有这个,如果你的列表中有(例如)<B>,那么你也会无意中将<BODY><BLOCKQUOTE>标记列入白名单。

我还在所有地方使用了占有量词(*+++?+),因为这个正则表达式的编写方式,我知道回溯将永远不会有用。如果它会失败,我希望它尽快失败。

既然我告诉你如何让正则表达式工作,那么我请你不要使用它。这项工作太复杂,太重要了,无法使用像正则表达式那样糟糕的工具。如果你真的从一本关于PHP安全性的书中得到了那个正则表达式,我建议你收回你的钱。