Domanda

Attualmente sto usando PHP e un'espressione regolare per eliminare tutti i commenti HTML da una pagina. La sceneggiatura funziona bene ... un po 'troppo bene. Elimina tutti i commenti inclusi i miei commenti condizionali nel. Ecco cosa ho:

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

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

Dato che il mio regex non è troppo caldo, ho problemi a cercare di capire come modificare lo schema per escludere commenti condizionali come:

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

Saluti

È stato utile?

Soluzione

Dato che i commenti non possono essere nidificati in HTML, una regex può fare il lavoro, in teoria. Tuttavia, l'utilizzo di un qualche tipo di parser sarebbe la scelta migliore, soprattutto se l'input non è garantito per essere ben formato.

Ecco il mio tentativo. Per abbinare solo i commenti normali, questo funzionerebbe. È diventato piuttosto un mostro, mi dispiace per quello. L'ho testato abbastanza ampiamente, sembra farlo bene, ma non do alcuna garanzia.

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

Spiegazione:

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

I passaggi n. 02 e n. 11 sono cruciali. # 02 si assicura che i seguenti caratteri non indichino un commento condizionale. Dopodiché, # 11 si assicura che i seguenti caratteri non indichino la fine del commento, mentre # 12 e # 13 causano la corrispondenza effettiva.

Richiedi con " globale " e "dotall" bandiere.

Per fare il contrario (abbina solo i commenti condizionali), sarebbe qualcosa del genere:

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

Spiegazione:

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

Ancora una volta, fai domanda con " global " e "dotall" bandiere.

Il passaggio n. 02 è dovuto al "livello inferiore rivelato". sintassi, vedere: " MSDN - Informazioni sui commenti condizionali " .

Non sono del tutto sicuro di dove gli spazi siano ammessi o previsti. Aggiungi \ s * all'espressione dove appropriato.

Altri suggerimenti

Se non riesci a farlo funzionare con un'espressione regolare o trovi che desideri conservare più commenti, puoi utilizzare preg_replace_callback . È quindi possibile definire una funzione per gestire i commenti singolarmente.

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

In sintesi, questa sembra essere la soluzione migliore:

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

Elimina tutti i commenti e lascia condizionali ad eccezione di quello in alto:

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

dove l'aggiunta sembra causare il problema.

Se qualcuno potesse suggerire la regex che lo prenderebbe in considerazione e lasciare anche quel condizionale in atto, sarebbe perfetto.

La soluzione di Tomalak sembra buona ma come principiante e senza ulteriori linee guida non so come implementarla, anche se mi piacerebbe provarla se qualcuno può approfondire su come applicarla?

Grazie

Non sono sicuro che al motore regex di PHP piacerà quanto segue, ma prova questo schema:

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

Qualcosa del genere potrebbe funzionare:

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

È uguale al tuo, tranne per il fatto che ignora i commenti che hanno una parentesi aperta immediatamente dopo il tag di inizio del commento.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top