7

我目前正在使用 PHP 和正则表达式从页面中删除所有 HTML 注释。该脚本运行良好......有点太好了。它会删除所有评论,包括我在 . 这是我所拥有的:

<?php
  function callback($buffer)
  {
        return preg_replace('/<!--(.|\s)*?-->/', '', $buffer);
  }

  ob_start("callback");
?>
... HTML source goes here ...
<?php ob_end_flush(); ?>

由于我的正则表达式不太热,我很难弄清楚如何修改模式以排除条件注释,例如:

<!--[if !IE]><!-->
<link rel="stylesheet" href="/css/screen.css" type="text/css" media="screen" />
<!-- <![endif]-->

<!--[if IE 7]>
<link rel="stylesheet" href="/css/ie7.css" type="text/css" media="screen" />
<![endif]-->

<!--[if IE 6]>
<link rel="stylesheet" href="/css/ie6.css" type="text/css" media="screen" />
<![endif]-->

干杯

4

5 回答 5

23

由于注释不能嵌套在 HTML 中,理论上,正则表达式可以完成这项工作。尽管如此,使用某种解析器将是更好的选择,尤其是在您的输入不能保证格式正确的情况下。

这是我的尝试。要仅匹配普通评论,这将起作用。它已经变成了一个怪物,对此感到抱歉。我已经对它进行了广泛的测试,它似乎做得很好,但我不做任何保证。

<!--(?!\s*(?:\[if [^\]]+]|<!|>))(?:(?!-->).)*-->

解释:

<!--                #01: "<!--"
(?!                 #02: look-ahead: a position not followed by:
  \s*               #03:   any number of space
  (?:               #04:   non-capturing group, any of:
    \[if [^\]]+]    #05:     "[if ...]"
    |<!             #06:     or "<!"
    |>              #07:     or ">"
  )                 #08:   end non-capturing group
)                   #09: end look-ahead
(?:                 #10: non-capturing group:
  (?!-->)           #11:   a position not followed by "-->"
  .                 #12:   eat the following char, it's part of the comment
)*                  #13: end non-capturing group, repeat
-->                 #14: "-->"

步骤#02 和#11 至关重要。#02 确保以下字符不表示条件注释。之后,#11 确保后面的字符不表示注释的结尾,而 #12 和 #13 导致实际匹配。

应用“global”和“dotall”标志。

做相反的事情(只匹配条件注释),它会是这样的:

<!(--)?(?=\[)(?:(?!<!\[endif\]\1>).)*<!\[endif\]\1>

解释:

<!                  #01: "<!"
(--)?               #02: two dashes, optional
(?=\[)              #03: a position followed by "["
(?:                 #04: non-capturing group:
  (?!               #05:   a position not followed by
    <!\[endif\]\1>  #06:     "<![endif]>" or "<![endif]-->" (depends on #02)
  )                 #07:   end of look-ahead
  .                 #08:   eat the following char, it's part of the comment
)*                  #09: end of non-capturing group, repeat
<!\[endif\]\1>      #10: "<![endif]>" or "<![endif]-->" (depends on #02)

同样,应用“global”和“dotall”标志。

步骤#02 是因为“downlevel-revealed”语法,请参阅:“MSDN - About Conditional Comments”

我不完全确定允许或预期的空间。在适当的地方添加\s*到表达式中。

于 2009-06-18T16:52:18.987 回答
2

如果你不能让它与一个正则表达式一起工作,或者你发现你想保留更多你可以使用的注释preg_replace_callback。然后,您可以定义一个函数来单独处理评论。

<?php
function callback($buffer) {
    return preg_replace_callback('/<!--.*-->/U', 'comment_replace_func', $buffer);
}

function comment_replace_func($m) {
    if (preg_match( '/^\<\!--\[if \!/i', $m[0])) {
        return $m[0];   
    }              

    return '';
}   

ob_start("callback");
?>

... HTML source goes here ...

<?php ob_end_flush(); ?>
于 2009-06-18T16:10:30.713 回答
1

总之,这似乎是最好的解决方案:

<?php
  function callback($buffer) {
    return preg_replace('/<!--[^\[](.|\s)*?-->/', '', $buffer);
  }
  ob_start("callback");
?>
... HTML source goes here ...
<?php ob_end_flush(); ?>

它去除了所有注释并留下除最上面的条件之外的条件:

<!--[if !IE]><!-->
<link rel="stylesheet" href="/css/screen.css" type="text/css" media="screen" />
<!-- <![endif]-->

额外的似乎导致问题的地方。

如果有人可以建议考虑到这一点的正则表达式并将该条件也保留在适当的位置,那将是完美的。

Tomalak 的解决方案看起来不错,但作为一个新手并且没有进一步的指导方针,我不知道如何实施它,尽管如果有人可以详细说明如何应用它,我想尝试一下?

谢谢

于 2009-06-23T08:46:03.210 回答
0

像这样的东西可能会起作用:

/<!--[^\[](.|\s)*?-->/

它与您的相同,只是它忽略了评论,评论开始标签后面有一个左括号。

于 2009-06-18T16:06:43.460 回答
0

我不确定 PHP 的正则表达式引擎是否会喜欢以下内容,但请尝试以下模式:

'/<!--(.|\s)*(\[if .*\]){0}(.|\s)*?-->/'
于 2009-06-18T16:07:04.583 回答