Удаление HTML-комментариев с помощью PHP, но с сохранением условий

StackOverflow https://stackoverflow.com/questions/1013499

Вопрос

В настоящее время я использую 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]-->

Ваше здоровье

Это было полезно?

Решение

Поскольку комментарии не могут быть вложены в 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 связан с синтаксисом «раскрытого на нижнем уровне», см.: «MSDN — об условных комментариях».

Я не совсем уверен, где разрешены или ожидаются пробелы.Добавлять \s* к выражению, где это уместно.

Другие советы

Если вы не можете заставить его работать с одним регулярным выражением или хотите сохранить больше комментариев, вы можете использовать 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(); ?>

Таким образом, это кажется лучшим решением:

<?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]-->

где дополнительное, по-видимому, вызывает проблему.

Если кто-нибудь может предложить регулярное выражение, которое примет это во внимание и оставит это условие на месте, тогда это было бы идеально.

Решение Томалака выглядит хорошо, но, будучи новичком и не имея дополнительных указаний, я не знаю, как его реализовать, хотя я хотел бы попробовать, может ли кто-нибудь рассказать, как его применить?

Спасибо

Я не уверен, понравится ли механизму регулярных выражений PHP следующее, но попробуйте этот шаблон:

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

Что-то вроде этого может сработать:

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

Он такой же, как ваш, за исключением того, что он игнорирует комментарии и имеет открывающую скобку сразу после начального тега комментария.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top