php
  • regex
  • string
  • replace
  • preg-replace
  • 2013-04-30 16 views 9 likes 
    9

    Questo è ciò che hoSostituire ogni personaggio con un elemento

    $str = 'Just a <span class="green">little</span> -text åäö width 123#'; 
    

    Questo è quello che mi serve

    Risultati in campate e spazi, potrei essere a capo pure.

    $result = '<span></span><span></span><span></span><span></span> <span></span> <span class="green"><span></span><span></span><span></span><span></span><span></span><span></span></span> <span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span> <span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span>'; 
    

    Ci si potrebbe chiedere che cosa possa essere necessario per questo. Voglio costruire una cosa dove mai il personaggio è rappresentato da un blocco. Sembrerà un po 'come Defrag su Windows XP.

    Domanda

    • sostituire ogni personaggio con <span></span>.
    • Non toccare l'arco HTML che già esiste nella stringa (potrebbe essere difficile?). Ci può essere più di un elemento HTML.
    • Non toccare spazi e newline.
    • Regexp dovrebbe farlo? o Xpath?

    Cosa ho fatto finora?

    ho trovato articoli sulla espressione regolare, ma non sostituendo tutti i caratteri (spazi estratto e ritorno a capo)

    $result = preg_replace("/???/", "<span></span>", $str); 
    print_r($result); 
    
    +0

    prova 'preg_replace ("/([^: lo spazio : \ n])/"," ", $ str);' [] è un set di caratteri,^NON è,: spazio: o \ s è uno spazio \ n è newline – Waygood

    +2

    Il "non toccare l'HTML che già esiste nella stringa "parte è dove le soluzioni regex causano problemi. Vuoi veramente usare un parser DOM, per iterare solo sopra i textnode e applicare una '/ \ S /' -> '' sostituzione su quelli. [Ecco una buona panoramica delle opzioni di analisi del DOM] (http://stackoverflow.com/questions/3577641/how-to-parse-and-process-html-xml) –

    +0

    C'è solo un intervallo HTML o ci sono Di Più ? – HamZa

    risposta

    1

    Non sono necessarie soluzioni regex per l'hacky. Un semplice ciclo for con una macchina a stati dovrebbe fare bene:

    define('STATE_READING', 1); 
    define('STATE_TAG', 2); 
    
    $str = 'Just a <span class="green">little</span> -text åäö width 123#'; 
    $result = ''; 
    
    $state = STATE_READING; 
    for($i = 0, $len = strlen($str); $i < $len; $i++) { 
        $chr = $str[$i]; 
    
        if($chr == '<') { 
         $state = STATE_TAG; 
         $result .= $chr; 
        } else if($chr == '>') { 
         $state = STATE_READING; 
         $result .= $chr; 
        } else if($state == STATE_TAG || strlen(trim($chr)) === 0) { 
         $result .= $chr; 
        } else { 
         $result .= '<span></span>'; 
        } 
    } 
    

    Questo ciclo è solo tenere traccia se stiamo leggendo un tag o un singolo carattere. Se è un tag (o spazio), aggiungi il carattere attuale, altrimenti aggiungi <span></span>.

    Risultati in:

    <span></span><span></span><span></span><span></span> <span></span> <span class="green"><span></span><span></span><span></span><span></span><span></span><span></span></span> <span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span><span></span> 
    
    +0

    Perché l'uso di definisce? –

    +1

    Preferisco i numeri magici. '$ state == STATE_TAG' mostra l'intento migliore di' $ stato == 2' o '$ stato == 'x''. – alexn

    1

    si tratta di un obbligo di utilizzare una sola espressione regolare?

    se non - si potrebbe sostituire sottostringa che è necessario al sicuro con qualche carattere unico, eseguire la sostituzione con espressioni regolari, mettere sottostringa al posto di quella char unica.

    Proprio come questo:

    $str2 = str_replace('<span class="green">little</span>', '$', $str); 
    $str3 = preg_replace("/([^\s\n\$])/", "<span></span>", $str2); 
    $result = str_replace('$', '<span class="green">little</span>', $str3); 
    

    vedere demo live http://codepad.viper-7.com/7wu9fd

    UPD:

    Forse dovrebbe essere considerata solo come suggerimento. Il mio suggerimento è stato quello di memorizzare substring (s) quello che doveva essere conservato, sostituire tutto il necessario, i valori memorizzati rimettere in stringa.

    $str = 'Just a <span class="green">little</span> -text åäö width 123#'; 
    
    preg_match_all('/<[^>]+>/', $str, $matches); 
    $storage=array(); 
    for($i=0, $n=count($matches[0]); $i<$n; $i++) 
    { 
        $key=str_repeat('$', $i+1); 
        $value=$matches[0][$i]; 
        $storage[$key]=$value; 
        $str=str_replace($value, $key, $str); 
    } 
    $storage=array_reverse($storage); 
    
    $str = preg_replace("/([^\s\n\$])/", "<span></span>", $str); 
    foreach($storage as $k=>$v) 
    { 
        $str=str_replace($k, $v, $str); 
    } 
    echo htmlspecialchars($str); 
    

    demo funzionante c'è http://codepad.viper-7.com/L4YZOz

    +0

    Soluzione interessante. Peccato che non sia un'opzione per me. Il "piccolo" può essere qualsiasi cosa e dovrebbe essere convertito anche in campate. –

    +0

    @ JensTörnell: vedere la mia risposta aggiornata –

    +0

    Sembra corretta. Votato finora. –

    0

    Mentre questo è probabilmente possibile con una regex, ma mi piacerebbe andare con un ciclo. codice di esempio è per set di caratteri a singolo byte, ma può essere modificata per multi-byte (ad esempio UTF-16) o variabile byte (ad esempio UTF-8) set di caratteri.

    $input = 'Just a <span class="green">little</span> -text åäö width 123#'; 
    $output = ''; 
    $length = strlen($input); 
    $i = 0; 
    $matches = array(); // preg_match variable 
    // While for finer control 
    while($i < $length) { 
        // Check for start of span tag, check for < character first for speed-up 
        if($input[$i] == "<" && preg_match("#<span[^>]*>.*</span>#siU", substr($input, $i), $matches) == 1) { 
         // Skip the span tag 
         $i = $i + strlen($matches[0]); 
         $output .= $matches[0]; 
        } else { 
         $output .= "<span></span>"; 
         $i++; 
        } 
    } 
    

    Working example

    +0

    Non ho testato il codice molto bene, potrebbero esserci alcune condizioni al contorno, ma l'idea dovrebbe essere chiara. – dtech

    0

    po 'di hack, ma provate questo:

    $str="Just a <span class=\"green\">little</span> -text åäö\n width 123#"; 
    
    // get all span tags 
    if(preg_match_all("/(\<span.*\<\/span\>)/", $str, $matches)) 
    { 
        // replace spans with # 
        $str=preg_replace_all("/(\<span.*\<\/span\>)/", "#", $str); 
    
        //print_r($matches); 
    } 
    // replace all non spaces, CR and # 
    $str=preg_replace("/[^\s\n#]/", "<span></span>", $str); 
    // replenish the matched spans 
    while(list($key,$value)=each($matches[0])) 
    { 
        $str=preg_replace('/#/', $value, $str, 1); 
    } 
    
    +0

    Non si interromperà se '$ str' contiene un' # 'in esso tra due tag span? – dtech

    +0

    Sì, se c'è un # all'esterno di un set , ecco perché è un hack – Waygood

    0

    Quindi ecco cosa mi è venuta con l'utilizzo preg_replace_callback():

    $str = 'Just a <span class="green">little</span>-text åäö width 123#<span>aaa</span> lol'; 
    
    // This requires PHP 5.3+ 
    $output = preg_replace_callback('#.*?(<span[^>]*>.*?</span>)|.*#is', function($m){ 
        if(!isset($m[1])){return preg_replace('/\S/', '<span></span>', $m[0]);} 
        $array = explode($m[1], $m[0]); 
        $array = preg_replace('/\S/', '<span></span>', $array); 
        return(implode($m[1], $array)); 
    }, $str); 
    echo($output); 
    

    uscita:

    <span></span><span></span><span></span><span></span> <span></span> <span class="green">little</span><span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span><span></span><span>aaa</span> <span></span><span></span><span></span> 
    
    2

    È possibile utilizzare preg_replace_callback()

    $str = 'Just a <span class="green">little</span> -text åäö width 123#'; 
    
    function replacement($matches) { 
          if (strlen($matches[0]) == 1) 
          { 
           return "<span></span>"; 
          } 
          else 
          { 
           return $matches[0]; 
          } 
    } 
    
    $result = preg_replace_callback("~<span.*?<\s*/\s*span>|\S~", "replacement", $str); 
    print_r($result); 
    

    Questo è solo calcolare la stringa di sostituzione dipende dalla partita. Se la lunghezza della corrispondenza è 1 (è stato trovato un carattere non di spazio bianco), sostituirlo con i tag "span", altrimenti è stato trovato un tag span, reinserirlo.

    +0

    +1 è necessario controllare $ matches [0] non è un CR/LF? – Waygood

    +0

    @Waygood, no perché '\ S' è un carattere non di spaziatura, i caratteri di nuova riga appartengono ai caratteri di spaziatura, non sono associati. – stema

    +0

    anche qualcos'altro appartiene a "caratteri bianchi"? se non è solo uno spazio e una nuova linea, ad es. tab \ t, quindi i risultati saranno errati? – Waygood

    0

    questo non è un metodo di espressione regolare hacky. Questa è una soluzione solida, concisa, a una sola riga, con una sola funzione, che evita di dover iterare una batteria di condizioni su ogni carattere in una stringa, conserva i tag e si prende cura dei caratteri multi-byte.

    La soluzione di alexn non mantiene la lunghezza del carattere visibile di åäö. La sua soluzione stamperà 6 tag di apertura e chiusura su schermo invece di solo 3. Questo perché le funzioni mb_ non vengono utilizzate. Su questo argomento, diffidare di tutti i metodi presenti in questa pagina che non utilizzano le funzioni di stringa con prefisso mb_.

    La mia soluzione suggerita sfrutterà la tecnica (*SKIP)(*FAIL) per ignorare/squalificare tutti i tag rilevati e quindi abbinare solo caratteri non di spazio bianco nella stringa.

    Codice: (Demo)

    $str = 'Just a <span class="green">little</span> -text åäö width 123#'; 
    var_export(preg_replace('/<[^>]*>(*SKIP)(*FAIL)|\S/','<span></span>',$str)); // no "u" flag means åäö will be span x6 
    echo "\n"; 
    var_export(preg_replace('/<[^>]*>(*SKIP)(*FAIL)|\S/u','<span></span>',$str)); // "u" flag means åäö will be span x3 
    

    uscita: (scorrere verso destra per vedere l'impatto della bandiera unicode sul modello)

    '<span></span><span></span><span></span><span></span> <span></span> <span class="green"><span></span><span></span><span></span><span></span><span></span><span></span></span> <span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span><span></span>' 
    // notice the number of replacements for åäö ->-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------111111111111122222222222223333333333333444444444444455555555555556666666666666 
    '<span></span><span></span><span></span><span></span> <span></span> <span class="green"><span></span><span></span><span></span><span></span><span></span><span></span></span> <span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span> <span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span><span></span>' 
    // notice the number of replacements for åäö ->-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------111111111111122222222222223333333333333 
    
    +0

    @ JensTörnell Quanti set di tag span si desidera vedere quando si sostituiscono i caratteri multibyte? 'åäö' dovrebbe diventare 3 set o 6 set? Mi sembra che ne vorreste solo tre perché non vi è alcun vantaggio aggiuntivo per sei. – mickmackusa

     Problemi correlati

    • Nessun problema correlato^_^