【问题标题】:Stripping HTML Comments With PHP But Leaving Conditionals使用 PHP 去除 HTML 注释但保留条件
【发布时间】:2010-11-04 01:14:13
【问题描述】:

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

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

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

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

<!--[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]-->

干杯

【问题讨论】:

    标签: php regex comments conditional strip


    【解决方案1】:

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

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

    <!--(?!\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”标志。

    相反(仅匹配条件 cmets),它会是这样的:

    <!(--)?(?=\[)(?:(?!<!\[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* 添加到表达式中。

    【讨论】:

    • 您好 Tomalak,感谢您的意见和详细解释。使正则表达式更容易:)。但是,我刚刚尝试了您的解决方案,除了空白页之外,它根本不显示任何内容。我正在使用的完整行是: return preg_replace(' ).)*-->', '', $buffer);这是正确的吗?
    • 我必须承认我以前没有遇到过 preg_replace,所以我一有机会就给文档一读。但是,出于这个特定问题的目的,您是否可以详细说明如何实现它?虽然它看起来比正则表达式更广泛,但听起来是一种有趣的方法,我想尝试一下。
    • 您现在有“机会”阅读文档:php.net/manual/en/function.preg-replace.php :))(也:php.net/manual/en/pcre.pattern.php
    • 尝试了很多其他正则表达式,但这个是终极的,它可以按我的意愿工作。
    【解决方案2】:

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

    <?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(); ?>
    

    【讨论】:

    • 我认为脚本应该像这样插入头部是否正确: /U', 'comment_replace_func' , $缓冲区); function comment_replace_func($m) { if (preg_match( '/^\ ... HTML 源代码在这里 ... 如果是这样,这不会删除任何 cmets 或似乎有任何影响?
    【解决方案3】:

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

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

    它去掉所有的 cmets 并留下除顶部之外的条件句:

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

    其他似乎导致问题的地方。

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

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

    谢谢

    【讨论】:

      【解决方案4】:

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

      '/<!--(.|\s)*(\[if .*\]){0}(.|\s)*?-->/'
      

      【讨论】:

      • 用这个替换我的正则表达式会提示 index.php 页面的下载保存弹出窗口,而不是呈现它。
      【解决方案5】:

      这样的事情可能会奏效:

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

      它和你的一样,只是它忽略了 cmets 在注释开始标记后面紧跟一个左括号。

      【讨论】:

      • 嗨,博登。此方法删除注释但留下 ,这意味着未应用样式表并且文档中到处都是箭头。
      • 你是这样称呼的吗? (不确定这段代码是否会在评论中发布) preg_replace('//', '', $buffer);
      • 是的,整行:return preg_replace('//', '', $buffer);这现在不会离开括号,但也不会成功地离开条件 cmets:
      • 嗯...我在这里运行它:solmetra.com/scripts/regex/index.php 使用 preg_replace 选项,我剪切并粘贴了您的代码 sn-p:它将条件保留在那里。
      • 听起来确实很奇怪。我刚刚复制并粘贴了您的代码并再次尝试,但同样的事情仍在发生。我的条件 cmets 与我原来的问题完全一样,但仍然像我上面的评论一样留在里面。
      猜你喜欢
      • 1970-01-01
      • 2013-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-30
      • 1970-01-01
      • 2010-11-08
      相关资源
      最近更新 更多