2011-12-13 12 views
5

Qui ho 2 metodi che utilizzano str_replace per sostituire stringhe in una determinata frase.Prestazioni di str_replace in PHP

// Method 1 
$phrase = "You should eat fruits, vegetables, and fiber every day."; 
$healthy = array("fruits", "vegetables", "fiber"); 
$yummy = array("pizza", "beer", "ice cream"); 
$phrase = str_replace($healthy, $yummy, $phrase); 

// Method 2 
$phrase = "You should eat fruits, vegetables, and fiber every day."; 
$phrase = str_replace("fruits", "pizza", $phrase); 
$phrase = str_replace("vegetables", "beer", $phrase); 
$phrase = str_replace("fiber", "ice cream", $phrase); 

Quale metodo è più efficace (in termini di tempo di esecuzione utilizzati & risorse)?

Supponiamo che la frase reale sia molto più lunga (ad esempio 50.000 caratteri) e che le parole da sostituire contengano molte più coppie.

Quello che sto pensando è che il metodo 2 chiama str_replace 3 volte, il che costerà più chiamate di funzione; d'altra parte il Metodo 1 crea 2 array, e il str_replace ha bisogno di analizzare 2 array in runtime.

+0

Il metodo 1 è più veloce. – djot

+1

non è una buona scelta, se hai una lunga stringa e hai più volte bisogno di str_replace, perché non salvare il risultato dopo str_replace? – ajreal

+0

Se crei ARRAY salutari e gustosi più e più volte nel ciclo, è più lento, non se li metti fuori. – djot

risposta

5

Preferirei utilizzare il metodo 1 come più pulito e più organizzato anche il Metodo 1 offre l'opportunità di utilizzare coppie di altre fonti, ad esempio: tabella di parolacce nel database. Metodo 2 richiederebbe un altro ciclo di sorta ..

<?php 
$time_start = microtime(true); 
for($i=0;$i<=1000000;$i++){ 
    // Method 1 
    $phrase = "You should eat fruits, vegetables, and fiber every day."; 
    $healthy = array("fruits", "vegetables", "fiber"); 
    $yummy = array("pizza", "beer", "ice cream"); 
    $phrase = str_replace($healthy, $yummy, $phrase); 
} 
$time_end = microtime(true); 
$time = $time_end - $time_start; 
echo "Did Test 1 in ($time seconds)\n<br />"; 



$time_start = microtime(true); 
for($i=0;$i<=1000000;$i++){ 
    // Method2 
    $phrase = "You should eat fruits, vegetables, and fiber every day."; 
    $phrase = str_replace("fruits", "pizza", $phrase); 
    $phrase = str_replace("vegetables", "beer", $phrase); 
    $phrase = str_replace("fiber", "ice cream", $phrase); 

} 
$time_end = microtime(true); 
$time = $time_end - $time_start; 
echo "Did Test 2 in ($time seconds)\n"; 
?> 

Did Test 1 a (3.6321988105774 secondi)

Did Test 2 a (2.8234610557556 secondi)


Edit: On ulteriore test stringa ripetuta a 50k, meno iterazioni e consigli da unjreal, la differenza è così minuscola.

<?php 
$phrase = str_repeat("You should eat fruits, vegetables, and fiber every day.",50000); 
$healthy = array("fruits", "vegetables", "fiber"); 
$yummy = array("pizza", "beer", "ice cream"); 

$time_start = microtime(true); 
for($i=0;$i<=10;$i++){ 
    // Method 1 
    $phrase = str_replace($healthy, $yummy, $phrase); 
} 
$time_end = microtime(true); 
$time = $time_end - $time_start; 
echo "Did Test 1 in ($time seconds)\n<br />"; 



$time_start = microtime(true); 
for($i=0;$i<=10;$i++){ 
    // Method2 
    $phrase = str_replace("fruits", "pizza", $phrase); 
    $phrase = str_replace("vegetables", "beer", $phrase); 
    $phrase = str_replace("fiber", "ice cream", $phrase); 

} 
$time_end = microtime(true); 
$time = $time_end - $time_start; 
echo "Did Test 2 in ($time seconds)\n"; 
?> 

Forse Test 1 in (1.1450328826904 secondi)

Forse Test 2 a (1.3119208812714 secondi)

+0

ma il tuo metodo di test show 2 è migliore? – ajreal

+0

Sì, ma l'id sacrifica quella frazione di 0,9 su iterazioni da 1 miglio per una migliore codifica e scalabilità. –

+1

Posso suggerire di mettere la dichiarazione dell'array al di fuori del ciclo? – ajreal

3

Anche se vecchia, questo benchmark non è corretto.

Grazie a utente anonimo:

"Questo test è sbagliato, perché quando prova 3 inizia $ frase è utilizzare i risultati del test di 2, in cui non v'è nulla di sostituire

quando aggiungo $. frase = "Dovresti mangiare frutta, verdura e fibra ogni giorno."; prima del test 3, i risultati sono: Test 1 in (4.3436799049377 secondi) Test 2 in (5.7581660747528 secondi) Test 3 in (7.5069718360901 secondi) "

 <?php 
     $time_start = microtime(true); 

     $healthy = array("fruits", "vegetables", "fiber"); 
     $yummy = array("pizza", "beer", "ice cream"); 

     for($i=0;$i<=1000000;$i++){ 
      // Method 1 
      $phrase = "You should eat fruits, vegetables, and fiber every day."; 
      $phrase = str_replace($healthy, $yummy, $phrase); 
     } 
     $time_end = microtime(true); 
     $time = $time_end - $time_start; 
     echo "Did Test 1 in ($time seconds)<br /><br />"; 



     $time_start = microtime(true); 
     for($i=0;$i<=1000000;$i++){ 
      // Method2 
      $phrase = "You should eat fruits, vegetables, and fiber every day."; 
      $phrase = str_replace("fruits", "pizza", $phrase); 
      $phrase = str_replace("vegetables", "beer", $phrase); 
      $phrase = str_replace("fiber", "ice cream", $phrase); 

     } 
     $time_end = microtime(true); 
     $time = $time_end - $time_start; 
     echo "Did Test 2 in ($time seconds)<br /><br />"; 




     $time_start = microtime(true); 
     for($i=0;$i<=1000000;$i++){ 
       foreach ($healthy as $k => $v) { 
        if (strpos($phrase, $healthy[$k]) === FALSE) 
        unset($healthy[$k], $yummy[$k]); 
       }           
       if ($healthy) $new_str = str_replace($healthy, $yummy, $phrase); 

     } 
     $time_end = microtime(true); 
     $time = $time_end - $time_start; 
     echo "Did Test 3 in ($time seconds)<br /><br />"; 

     ?> 

Test 1 in (3.5785729885101 seco nds)

Did Test 2 a (3.8501658439636 secondi)

Did Test 3 in (0.13844394683838 secondi)

1

@djot si dispone di un errore nella

<?php 
    foreach ($healthy as $k => $v) { 
     if (strpos($phrase, $healthy[$k]) === FALSE) 
      unset($healthy[$k], $yummy[$k]); 
     } 

qui abbiamo una versione fissa e meglio/semplice nuovo test 4

<?php 
$time_start = microtime(true); 

     $healthy = array("fruits", "vegetables", "fiber"); 
     $yummy = array("pizza", "beer", "ice cream"); 

     for($i=0;$i<=1000000;$i++){ 
      // Method 1 
      $phrase = "You should eat fruits, vegetables, and fiber every day."; 
      $phrase = str_replace($healthy, $yummy, $phrase); 
     } 
     $time_end = microtime(true); 
     $time = $time_end - $time_start; 
     echo "Did Test 1 in ($time seconds)". PHP_EOL. PHP_EOL; 



     $time_start = microtime(true); 
     for($i=0;$i<=1000000;$i++){ 
      // Method2 
      $phrase = "You should eat fruits, vegetables, and fiber every day."; 
      $phrase = str_replace("fruits", "pizza", $phrase); 
      $phrase = str_replace("vegetables", "beer", $phrase); 
      $phrase = str_replace("fiber", "ice cream", $phrase); 

     } 
     $time_end = microtime(true); 
     $time = $time_end - $time_start; 
     echo "Did Test 2 in ($time seconds)" . PHP_EOL. PHP_EOL; 




     $time_start = microtime(true); 
     for($i=0;$i<=1000000;$i++){ 
      $a = $healthy; 
      $b = $yummy; 
       foreach ($healthy as $k => $v) { 
        if (strpos($phrase, $healthy[$k]) === FALSE) 
        unset($a[$k], $b[$k]); 
       }           
       if ($a) $new_str = str_replace($a, $b, $phrase); 

     } 
     $time_end = microtime(true); 
     $time = $time_end - $time_start; 
     echo "Did Test 3 in ($time seconds)". PHP_EOL. PHP_EOL; 



     $time_start = microtime(true); 
     for($i=0;$i<=1000000;$i++){ 
      $ree = false; 
      foreach ($healthy as $k) { 
       if (strpos($phrase, $k) !== FALSE) { //something to replace 
        $ree = true; 
        break; 
       } 
      }           
      if ($ree === true) { 
       $new_str = str_replace($healthy, $yummy, $phrase); 
      } 
     } 
     $time_end = microtime(true); 
     $time = $time_end - $time_start; 
     echo "Did Test 4 in ($time seconds)". PHP_EOL. PHP_EOL; 

Test 1 in (0,38219690322876 seco nds)

Test 2 in (0.42352104187012 secondi)

Forse Test 3 a (0.47777700424194 secondi)

Did Test 4 a (0.19691610336304 secondi)

0

Anche se non ha chiesto direttamente nella questione, l'OP fa Stato:

Supponiamo che la frase reale sia molto più lunga (ad esempio 50.000 caratteri) e le parole da sostituire abbiano molte più coppie.

In questo caso, se non avete bisogno (o vogliono) rimontaggi all'interno di sostituzioni, può essere molto più efficiente di utilizzare una soluzione preg_replace_callback in modo che l'intera stringa si elabora solo una volta, non una sola volta per ogni coppia di sostituzioni.

Ecco una funzione generica che nel mio caso con una stringa da 1,5 Mb e ~ 20.000 coppie di sostituzioni era circa 10 volte più veloce, anche se poiché era necessario dividere le sostituzioni in blocchi a causa di errori di "espressione regolare troppo grandi", potrebbe hanno fatto sostituzioni indeterminatamente con sostituzioni (nel mio caso particolare questo non era possibile, tuttavia).

Nel mio caso particolare sono stato in grado di ottimizzare ulteriormente questo a un guadagno di prestazioni di circa 100x, perché le mie stringhe di ricerca seguivano tutte un particolare schema. (Versione PHP 7.1.11 su Windows 7 a 32 bit.)

function str_replace_bulk($search, $replace, $subject, &$count = null) { 
    // Assumes $search and $replace are equal sized arrays 
    $lookup = array_combine($search, $replace); 
    $result = preg_replace_callback(
    '/' . 
     implode('|', array_map(
     function($s) { 
      return preg_quote($s, '/'); 
     }, 
     $search 
    )) . 
    '/', 
    function($matches) use($lookup) { 
     return $lookup[$matches[0]]; 
    }, 
    $subject, 
    -1, 
    $count 
); 
    if (
    $result !== null || 
    count($search) < 2 // avoid infinite recursion on error 
) { 
    return $result; 
    } 
    // With a large number of replacements (> ~2500?), 
    // PHP bails because the regular expression is too large. 
    // Split the search and replacements in half and process each separately. 
    // NOTE: replacements within replacements may now occur, indeterminately. 
    $split = (int)(count($search)/2); 
    error_log("Splitting into 2 parts with ~$split replacements"); 
    $result = str_replace_bulk(
    array_slice($search, $split), 
    array_slice($replace, $split), 
    str_replace_bulk(
     array_slice($search, 0, $split), 
     array_slice($replace, 0, $split), 
     $subject, 
     $count1 
    ), 
    $count2 
); 
    $count = $count1 + $count2; 
    return $result; 
} 
Problemi correlati