首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 正則移除 HTML 註解進階技巧:處理條件註解、腳本內註解、多行註解

     編輯:PHP 綜合知識

單純用 //s 移除 HTML 註解會誤傷條件註解 <!--[if IE]>、腳本內註解 <script><!-- ... --></script>。本文逐步構建精準正則,層層排除特殊情況,實現只移除真正的 HTML 註解。

問題層層遞進

$html = '<!-- 普通註解 -->內容<!-- 另一個 -->';

// 1. 貪婪匹配錯誤:吞掉中間內容
preg_replace('#<!--.*-->#', '', $html); 
// 結果:'內容' (錯誤,第一個註解匹配到最後一個 -->)

// 2. 非貪婪修正:正確處理多個註解
preg_replace('#<!--.*?-->#', '', $html); 
// 結果:'內容' (正確)

// 3. 條件註解問題:<!--[if IE]>...<![endif]-->
$html2 = '<!--[if IE 9]>IE9專用<![endif]-->正常內容';
preg_replace('#<!--.*?-->#', '', $html2);
// 結果:'正常內容' (條件註解被誤刪,可能破壞 IE 相容性)

// 4. 腳本內註解問題
$html3 = '<script><!-- 舊瀏覽器隱藏腳本 --> console.log(1); //--></script>';
preg_replace('#<!--.*?-->#', '', $html3);
// 結果:'<script> console.log(1); //--></script>' (腳本結構被破壞)

進階正則構建

步驟 1:排除條件註解開頭 [ 或 !

// 模式:<!-- 後面不接 [ 或 !
$pattern1 = '#<!--[^\[!].*?-->#s';

步驟 2:排除腳本結束標記 //-->

// 模式:不包含 //--> 的註解內容
$pattern2 = '#<!--[^\[!].*?(?

步驟 3:完整最終版

function stripHtmlComments(string $html): string {
    // 核心正則:移除標準 HTML 註解,保留條件註解、腳本內註解
    $pattern = '#<!--(?![\[!])(?:(?!-->).)*?(?

測試驗證

<?php
$testCases = [
    '基本' => '<!-- 註解 -->保留',
    '多個' => '<!-- A -->中間<!-- B -->尾',
    '條件註解' => '<!--[if IE]>IE內容<![endif]-->保留',
    '腳本註解' => '<script><!-- 隱藏 --> code(); //--></script>',
    '巢狀註解' => '<!-- 外層 <!-- 內層 --> 外層尾 -->', // HTML 不支援巢狀,瀏覽器以第一個 --> 為結束
    '混合' => '<!-- 刪除 --><div>保留</div><!--[if IE]>保留<![endif]--><script><!--保留--></script>',
];

foreach ($testCases as $name => $html) {
    $result = stripHtmlComments($html);
    echo "=== {$name} ===\n";
    echo "原始: {$html}\n";
    echo "結果: {$result}\n\n";
}
?>

輸出結果

=== 基本 ===
原始: <!-- 註解 -->保留
結果: 保留

=== 多個 ===
原始: <!-- A -->中間<!-- B -->尾
結果: 中間尾

=== 條件註解 ===
原始: <!--[if IE]>IE內容<![endif]-->保留
結果: <!--[if IE]>IE內容<![endif]-->保留  ✓ 保留

=== 腳本註解 ===
原始: <script><!-- 隱藏 --> code(); //--></script>
結果: <script><!-- 隱藏 --> code(); //--></script>  ✓ 保留

=== 巢狀註解 ===
原始: <!-- 外層 <!-- 內層 --> 外層尾 -->
結果:  外層尾 -->  (符合瀏覽器行為:第一個 --> 結束)

=== 混合 ===
原始: <!-- 刪除 --><div>保留</div><!--[if IE]>保留<![endif]--><script><!--保留--></script>
結果: <div>保留</div><!--[if IE]>保留<![endif]--><script><!--保留--></script>  ✓ 完美

正則元件速查

語法名稱作用
(?!...)負向前瞻斷言後面不匹配...
(?負向後顧斷言前面不匹配...
(?:...)非捕獲群組分組不佔用反向引用編號
.*?非貪婪匹配盡可能少匹配
s 修飾符PCRE_DOTALL. 匹配換行符

替代方案:DOMDocument (最準確)

function stripCommentsDom(string $html): string {
    $dom = new DOMDocument();
    @$dom->loadHTML('' . $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    
    $xpath = new DOMXPath($dom);
    $comments = $xpath->query('//comment()');
    
    foreach ($comments as $comment) {
        // 保留條件註解:包含 [if 或 [endif
        $text = $comment->nodeValue;
        if (strpos($text, '[if') !== false || strpos($text, '[endif') !== false) {
            continue;
        }
        $comment->parentNode->removeChild($comment);
    }
    
    return $dom->saveHTML();
}

效能對比

preg_replace 正則 : ~0.5 ms / 10KB HTML
DOMDocument 解析   : ~3 ms / 10KB HTML (含解析開銷)
HTMLPurifier       : ~50 ms / 10KB HTML (完整 XSS 防護)

精準的正則利用負向前瞻/後顧斷言優雅解決 HTML 註解移除的邊界情況,效能優於 DOM 解析,適合高頻處理場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved