2011-12-13 8 views
5

ここには、str_replaceを使用して2つの方法があり、指定されたフレーズの文字列を置き換えます。 (使用される実行時間&資源の面で)、より効率的である方法PHPのstr_replaceの性能

// 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); 

実際のフレーズがはるかに長く(たとえば50,000文字)、置き換える単語がさらに多くのペアを持つとします。

私が考えているのは、メソッド2がを3回呼び出すため、より多くの関数呼び出しが必要になることです。一方、方法1は2つのアレイを作成し、str_replaceは実行時に2つのアレイを解析する必要があります。

+0

方法1は高速です。 – djot

+1

長い文字列があり、繰り返しstr_replaceが必要な場合は、str_replaceの後に結果を保存するのはなぜですか? – ajreal

+0

ARRAYを作成してループ内に何度も何度もやっていたら、遅くなります。 – djot

答えて

5

メソッド1をクリーナーとして使用することをお勧めします。また、より組織化された方法1は、データベース内の悪いワードテーブルなどの他のソースからのペアを使用する機会を与えます。方法2 ..一種の別のループを必要とする

<?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"; 
?> 

なかったのTest 1(3.6321988105774秒)

なかった(2.8234610557556秒)でのテスト2


編集:さらにテストで 50kに反復された文字列、少ない反復とアドバイスからのアドバイス、その違いは非常に小さいです。

<?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"; 
?> 

は(1.1450328826904秒)でテスト1を行った

でも古い場合、このベンチマークは間違っている(1.3119208812714秒)で

+0

しかし、あなたのテストショーの方法2はより良い性能ですか? – ajreal

+0

ええ、しかし、より良いコーディングとスケーラビリティのために、1milの繰り返しで0.9分の1秒を犠牲にしています。 –

+1

配列宣言をループ外に置くことを提案できますか? – ajreal

3

をテスト2を行いました。匿名ユーザーへ

ありがとう:。テスト3開始$フレーズがここで交換するものは何もない、試験2の結果を使用しているとき

私は$を追加するため

「このテストは、間違っていますフレーズ=「毎日果物、野菜、繊維を食べるべきです」;テスト3の前に、テスト1は(4.3436799049377秒)、テスト2は(5.7581660747528秒)、テスト3は(7.5069718360901秒)

 <?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 />"; 

     ?> 

(3.5785729885101 seco

は(3.8501658439636秒でテスト2 DID NDS))

は(0.13844394683838秒でテスト3 DID)あなたは

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

にエラーが発生している@djot

1

は、ここでは、固定されたバージョンを持っていますより良い/簡単な新しいテスト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; 

テスト1を(0.38219690322876 seco nds)

試験2を(0。直接質問に尋ねていないが、42352104187012秒)

がでテスト3(0.47777700424194秒)テスト4でした

中(0.19691610336304秒)

0

をした、OPはない状態:

実際のフレーズがはるかに長く(例えば50,000文字)、置き換える単語がより多くのペアを持つとします。あなたが必要とする(またはしたい)代替品の中に交換していない場合は、文字列全体が唯一の各ペアのためではありません一度、一度に処理されるように

その場合には、それはpreg_replace_callbackソリューションを使用することがはるかに効率的かもしれ置き換えの。

ここでは、「正規表現が大きすぎます」というエラーのために、置換文字をチャンクに分割する必要があるため、1.5Mbの文字列と約20,000ペアの置換えを持つ一般的な関数が約10倍高速でした私の場合はこれは不可能でしたが、置換の中で不確定に置き換えられました。

私の特定のケースでは、検索文字列がすべて特定のパターンに従っているため、これをさらに100倍のパフォーマンス向上にさらに最適化できました。 (Windows 7 32ビット版PHP 7.1.11)

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; 
}