Decapagem comentários HTML Com PHP Mas Conditionals Deixando
-
06-07-2019 - |
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
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.