Pergunta

Atualmente estou usando PHP e uma expressão regular para retirar todos os comentários HTML de uma página. O script funciona bem ... um pouco bem demais. Ele retira todos os comentários, incluindo os meus comentários condicionais no. Aqui está o que eu tenho:

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

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

Desde a minha regex não está muito quente que eu estou tendo problemas para tentar descobrir como modificar o padrão para excluir comentários condicionais, tais como:

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

Felicidades

Foi útil?

Solução

Uma vez que os comentários não podem ser aninhados em HTML, um regex pode fazer o trabalho, em teoria. Ainda assim, usando algum tipo de analisador seria a melhor escolha, especialmente se sua entrada não é garantido para ser bem formado.

Aqui é a minha tentativa para ele. Para corresponder apenas comentários normais, isso iria funcionar. Tornou-se bastante um monstro, desculpe por isso. Eu testei bastante extensa, parece fazê-lo bem, mas eu não dão nenhuma garantia.

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

Explicação:

<!--                #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: "-->"

Passos # 02 e # 11 são cruciais. # 02 garante que os seguintes caracteres não indicam um comentário condicional. Depois disso, # 11 garante que os seguintes caracteres não indicam o final do comentário, enquanto # 12 e # 13 causa a correspondência real.

Aplicar com "global" e "dotall" bandeiras.

Para fazer o oposto (coincidir com apenas comentários condicionais), seria algo como isto:

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

Explicação:

<!                  #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)

Mais uma vez, aplicar com "global" e "dotall" bandeiras.

Etapa # 02 é por causa da sintaxe "-nível inferior revelado", veja: "MSDN - Sobre condicional Comentários"

.

Eu não sou inteiramente certo onde são permitidos espaços ou esperado. Adicionar \s* à expressão se for o caso.

Outras dicas

Se você não pode obtê-lo para trabalhar com uma expressão regular ou você achar que você deseja preservar mais comentários você poderia usar preg_replace_callback . Você pode, então, definir uma função para lidar com os comentários individualmente.

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

Em resumo esta parece ser a melhor solução:

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

Ele retira todos os comentários e folhas condicionais com exceção da parte superior um:

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

onde o adicional parece estar causando o problema.

Se alguém pode sugerir o regex que levar isso em conta e deixar que condtional no lugar também, em seguida, que seria perfeito.

solução parece ser bom de Tomalak mas como um novato e não mais diretrizes Eu não sei como implementá-lo, embora eu gostaria de experimentá-lo se alguém pode elaborar sobre como aplicá-lo?

Graças

Eu não tenho certeza se o motor regex do PHP será como o seguinte, mas tente este padrão:

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

Algo como este trabalho poder:

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

É a mesma que a sua, exceto que ele ignora os comentários têm um colchete de abertura imediatamente após a tag comentário início.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top