Pregunta

Actualmente estoy usando PHP y una expresión regular para eliminar todos los comentarios HTML de una página. El guión funciona bien ... un poco demasiado bien. Elimina todos los comentarios, incluidos mis comentarios condicionales en el. Esto es lo que tengo:

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

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

Dado que mi expresión regular no es demasiado alta, tengo problemas para tratar de descubrir cómo modificar el patrón para excluir comentarios condicionales 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]-->

Saludos

¿Fue útil?

Solución

Dado que los comentarios no pueden anidarse en HTML, una expresión regular puede hacer el trabajo, en teoría. Aún así, usar algún tipo de analizador sería la mejor opción, especialmente si no se garantiza que su entrada esté bien formada.

Aquí está mi intento de hacerlo. Para hacer coincidir solo los comentarios normales, esto funcionaría. Se ha convertido en un monstruo, lo siento. Lo he probado bastante, parece que funciona bien, pero no garantizo.

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

Explicación:

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

Los pasos # 02 y # 11 son cruciales. # 02 se asegura de que los siguientes caracteres no indiquen un comentario condicional. Después de eso, # 11 se asegura de que los siguientes caracteres no indiquen el final del comentario, mientras que # 12 y # 13 causan la coincidencia real.

Aplicar con " global " y "dotall" banderas.

Para hacer lo contrario (hacer coincidir solo los comentarios condicionales), sería algo como esto:

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

Explicación:

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

Nuevamente, aplique con " global " y "dotall" banderas.

El paso # 02 se debe a la "bajada de nivel revelado" sintaxis, consulte: " MSDN - Acerca de los comentarios condicionales " .

No estoy completamente seguro de dónde se permiten o esperan espacios. Agregue \ s * a la expresión donde corresponda.

Otros consejos

Si no puede hacer que funcione con una expresión regular o si desea conservar más comentarios, puede usar preg_replace_callback . Luego puede definir una función para manejar los comentarios 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(); ?>

En resumen, esta parece ser la mejor solución:

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

Elimina todos los comentarios y deja condicionales, excepto el superior:

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

donde el adicional parece estar causando el problema.

Si alguien puede sugerir la expresión regular que tomaría esto en cuenta y dejar ese condimento en su lugar también, entonces sería perfecto.

La solución de Tomalak se ve bien, pero como novato y sin pautas adicionales, no sé cómo implementarla, aunque me gustaría probarla si alguien puede dar más detalles sobre cómo aplicarla.

Gracias

No estoy seguro de si el motor de expresiones regulares de PHP le gustará lo siguiente, pero intente este patrón:

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

Algo como esto podría funcionar:

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

Es igual que el tuyo, excepto que ignora los comentarios que tienen un paréntesis de apertura inmediatamente después de la etiqueta de inicio de comentarios.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top