Question

J'utilise actuellement PHP et une expression régulière pour supprimer tous les commentaires HTML d'une page. Le script fonctionne bien ... un peu trop bien. Il supprime tous les commentaires, y compris mes commentaires conditionnels, dans le. Voici ce que j'ai:

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

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

Comme ma regex n'est pas trop chaude, j'ai du mal à comprendre comment modifier le motif pour exclure les commentaires conditionnels tels que:

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

Cheers

Était-ce utile?

La solution

Comme les commentaires ne peuvent pas être imbriqués en HTML, une expression rationnelle peut faire le travail, en théorie. Néanmoins, il serait préférable d’utiliser un analyseur syntaxique, en particulier si votre contribution n’est pas garantie.

Voici ma tentative. Pour correspondre uniquement aux commentaires normaux, cela fonctionnerait. C'est devenu tout à fait un monstre, désolé pour cela. Je l'ai assez bien testé, il semble bien le faire, mais je ne donne aucune garantie.

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

Explication:

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

Les étapes 02 et 11 sont cruciales. # 02 s'assure que les caractères suivants n'indiquent pas un commentaire conditionnel. Après cela, # 11 s'assure que les caractères suivants n'indiquent pas la fin du commentaire, tandis que # 12 et # 13 provoquent la correspondance réelle.

Appliquer avec "global" et "dotall" drapeaux.

Pour faire le contraire (ne faire correspondre que les commentaires conditionnels), cela ressemblerait à ceci:

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

Explication:

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

Encore une fois, appliquez-le avec "global". et "dotall" drapeaux.

L’étape n ° 02 est due au message "révélé au niveau inférieur". syntaxe, voir: & MSDN - À propos des commentaires conditionnels " .

Je ne sais pas exactement où les espaces sont autorisés ou attendus. Ajoutez \ s * à l'expression, le cas échéant.

Autres conseils

Si vous ne pouvez pas le faire fonctionner avec une seule expression régulière ou si vous souhaitez conserver davantage de commentaires, vous pouvez utiliser . preg_replace_callback . Vous pouvez ensuite définir une fonction pour gérer les commentaires individuellement.

<?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 résumé, cela semble être la meilleure solution:

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

Il supprime tous les commentaires et laisse les conditionnels à l'exception du premier:

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

où le supplément semble causer le problème.

Si quelqu'un peut suggérer la regex qui tienne compte de cela et la laisse également en place, alors ce serait parfait.

La solution de Tomalak a l'air bien, mais en tant que débutant et sans autre directive, je ne sais pas comment la mettre en œuvre, bien que j'aimerais l'essayer si quelqu'un peut élaborer sur la façon de l'appliquer.

Merci

Je ne sais pas si le moteur de regex de PHP va aimer ce qui suit, mais essayez ce modèle:

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

Quelque chose comme ça pourrait marcher:

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

C'est la même chose que la vôtre, sauf qu'elle ignore que les commentaires ont un crochet ouvrant immédiatement après la balise de début de commentaire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top