php preg_replace_callback 删除 <script> 标签以外的评论

php preg_replace_callback Remove comments except from <script> tag

我想使用 preg_replace_callback 删除 html 评论。但我也想保留 <script> 元素内的注释,例如:

b/w <script> <!-- Keep Me--></script >

我的代码:

$str = '
    <script>
    <!-- keep1 -->
    keep </script> <!-- del me1 --> <body> <script> <!-- Keep2 --></script> <!-- Del me2 --> <script><!-- Keep3 --></script> </body><!-- del me 3 -->';


$str =    preg_replace_callback('/(<([^script]\/?)(\w|\d|\n|\r|\v)>)*((.*(<?!--.*-->)|(\w|\d|\n|\r|\v)*)+)(<\/?[^script](\w|\d)*>)/s',
    function($matches) {
        print_r($matches);
        return preg_replace('/<!--.*?-->/s', ' ', $matches[2]);
    }, $str);

您不能尝试使用此代码:

$str= preg_replace('/<!--(\w|\s)*-->/', '', $str);

并且在您的 Javascript 中,您可以使用(而不是 <!-- -->):

/* Keep me comment */

从技术上讲,脚本标签之间的 "html comments" 不再是 html 注释。如果您使用 DOM 方法,这些评论不是 selected:

$dom = new DOMDocument;
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

$xp = new DOMXPath($dom);
$comments = $xp->query('//comment()');

foreach ($comments as $comment) {
    $comment->parentNode->removeChild($comment);
}

$result = $dom->saveHTML();

关于条件注释:

如果要保留条件注释,需要检查注释的开头。您可以通过两种方式完成。

第一种方法是在foreach循环中检查注释,当测试是否定的时候,你删除节点。

但是由于您使用的是 XPath 方式(即 select 您想要的一劳永逸),为了遵循相同的逻辑,您可以将 XPath 查询更改为:

//comment()[not(starts-with(., "[if") or starts-with(., "[endif]"))]

方括号之间的内容称为"predicate"(当前元素的条件),点表示当前元素或其文本内容(取决于上下文)

但是,如果这在大多数情况下都有效,最轻微的前导 space 都会使其失败。您需要比 starts-with.

更灵活的东西

可以像这样注册您自己的 php 函数以在 XPath 查询中使用:

function isConditionalComment($commentNode) {
    return preg_match('~\A(?:\[if\s|\s*<!\[endif])~', $commentNode[0]->nodeValue);
}

$dom = new DOMDocument;
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

$xp = new DOMXPath($dom);

$xp->registerNamespace('php', 'http://php.net/xpath');
$xp->registerPHPFunctions('isConditionalComment');

$comments = $xp->query('//comment()[not(php:function("isConditionalComment", .))]');

foreach ($comments as $comment) {
    $comment->parentNode->removeChild($comment);
}

注意:DOMDocument 不支持不是 HTML 评论的默认 Microsoft 语法(没有人使用的语法):

<![if !IE]>
<link href="non-ie.css" rel="stylesheet">
<![endif]>

此语法会导致警告(因为它不是 HTML)并且 "tag" 会被忽略并从 DOM 树中消失。