6

非常に大きな文字列$strがあり、そのかなりの部分(たとえば、文字列全体、ただし最初の3バイトは含まない)を関数に渡す必要があるとします。それを行う方法substr

consumer_function(substr($str, 3));

substr結果を返す前に、最初の文字列から新しい文字列に文字をコピーするように見えるため、効率的ではないようです。その文字列の大部分を過度にコピーせずに関数に渡す方法はありますか?その関数のコードを変更することはできません。

4

4 に答える 4

3

ここに問題があるとは思いません。あなたは問題があると推測していて、問題があると考える理由はありません。

「効率が悪いようです」は問題ではありません。それを測定して遅いことがわかった場合は、問題があります。次に、コードでXDebugなどのプロファイラーを使用して、コードのどの部分が遅いかを確認します。

問題がなければ解決できません。おそらく遅いと思われるかもしれないことを推測しても、問題があるとは限りません。

最適化クラブのルール:

  1. 最適化クラブの最初のルールは、最適化しないことです。
  2. 最適化クラブの2番目のルールは、測定せずに最適化しないことです。
  3. アプリが基盤となるトランスポートプロトコルよりも高速に実行されている場合、最適化は終了しています。
  4. 一度に1つの要因。
  5. マーケットロイドもマーケットロイドスケジュールもありません。
  6. テストは必要な限り続行されます。
  7. これがOptimizationClubでの最初の夜である場合は、テストケースを作成する必要があります。
于 2013-01-03T02:04:53.320 に答える
1

$strあなたができる別の変数を作成することなく、あなたに取り組んでいます:

for($i=1;$i<=$no;$i++) $str[strlen($str)-$i]=null;
$str=rtrim($str);

$no最後から最後の文字を削る

また:

for($i=0;$i<$no;$i++) $str[$i]=null;
$str=ltrim($str);

そこから最初の文字を削ります。

アップデート:

テスト A: 文字列の先頭から 30 文字を削る

テスト ケース 1: substr($str,30)

52784749 bytes of data
0.72129082679749s execution time
52903844 bytes of ram used

テスト ケース 2: null 化文字列 char と ltrim を使用したループ

52784749 bytes of data
0.23676204681396s execution time
52904276 bytes of ram used

テスト B: 文字列の末尾から 30 文字を削る

テスト ケース 1: substr($str,0,-30)

52784749 bytes of data
0.83467292785645s execution time
52903924 bytes of ram used

テスト ケース 2: null 化文字列 char と rtrim を使用したループ

52784749 bytes of data
0.27498316764832s execution time
52904340 bytes of ram used

この種のマイクロ最適化が本当に必要な場合の正当な質問は、このソリューションで 3 倍の処理時間を達成し 1.2Mb の小さなデータセットでさらに改善 (最大 40 倍) しました。
もう少しテストが必要ですが、実行可能なオプションのようです。

更新 2:

Grigory が指摘したように、メモリは速度
よりも大きな問題であり、Fergus はltrim() のメモリ フットプリントに気付きまし増加します。

一方、trim() を使用しないと、同じ長さの文字列になり、ヌル文字になりますが、速度が向上し、メモリが節約されます。

更新3:

nullfalse、および " \x08 " (BackSpace chr)でも機能します。
var_dump() は、元の文字列と同じ長さの文字列を報告しますが、引用符で囲まれた値は、あなたが期待するものです: 興味のある部分のみです.

質問が[クローズ]されたのは残念です:(

于 2013-01-03T00:33:03.340 に答える
1

「それを機能させてから、それを完璧にする」

まじめな話 - 時期尚早の最適化は、うまくいく方法ではありません。明らかにパフォーマンス ヒットがあると思わない限り(顕著なヒット)、そのままにしておきます。あまり使われないトリックを使って非常に一般的なことを行うと、再訪したときにメンテナンスの悪夢が発生するだけです。

デフォルトで使用できる代替メソッドはありません。PHP Web サイトでString Functionsを確認すると、使用可能なものが表示されます。

ただし、配列表記を使用して文字列を操作できます。

$str[ index ] 

例えば:

$str = "abc";
$str[0] // a
$str[1] // b
$str[2] // c

と組み合わせるとunset()、文字列から特定の項目を手動で設定解除することが完全に可能です..

$str = "abc";
unset( $str[1] ); // $str = "ac" now.

基本的なループをスローすると、これを使用できます。あなたの例では、3を削除したかったので、次のようにそれを達成します:(注意、配列表記=インデックスは0から始まります!!)

for( $i=0; $i<=2; $i++ )
  unset( $str[i] );

ただし、元の文字列が失われることを覚えておいてください。後で必要になる可能性のあるデータはありますか? うん、なくなった。

しかし、もし私があなただったら、私は固執するでしょうsubstr()

編集: Grigory は、これが PHP 5.3 では機能しないことをコメントで指摘しています。これは、PHP ドキュメントに記載されているように奇妙です:

文字列アクセスと文字による変更

$str[42] のように、角かっこを使用して、文字列の後に目的の文字のゼロベースのオフセットを指定することにより、文字列内の文字にアクセスして変更できます。この目的では、文字列を文字の配列と考えてください。関数 substr() および substr_replace() は、複数の文字を抽出または置換する場合に使用できます。

ですから、これは本当に固執するもう 1 つの理由substr()です。私は今、少し興味があります。そのため、この動作が原因でのみ発生するかどうかを確認してみますunset()。リポートします!

更新:予想どおり、この動作の原因はunset()- 実際にはあまりにも驚いたとは言えません。

**Fatal errors:** [type:1] -- Cannot unset string offsets -- at line 7

私のテスト ケースは、こちらのphpFiddleで確認できます。

したがって、結論として、言語にネイティブに組み込まれているこれを実行できる文字列関数はなく、文字列を 1 文字ずつ操作して実行することはできません。推奨される方法に固執します。

于 2013-01-03T00:38:47.340 に答える
0

以前の回答に基づいています。php が配列のような文字列を試行することを信頼できる場合、つまり、内部重複なしで、さらに 2 つの解決策をテストする必要があります。$str元の文字列を何度も書き直すことに注意してください。

$str         = "abcdefghi"; // a given string 
$set_strip   = 3; // how many chars strip

$strlen  = strlen($str);
$strip   = $strlen - $set_strip;

// test before commit errors    
if ($strip > 0 && $strip <= $strlen)
{
    // SOL. 1.- using str_split with $strip as 2º parameter (trusting strrev() acts efficienly)
    $str             = strrev($str); // reverse string
    $str             = str_split($str, $strip); // split into a array with 2 elements
    $str             = strrev($str[0]); // back to original order

    // SOL. 2.- shortening array $set_strip times
    $str             = str_split($str);
    for ($i = 0; $i < $set_strip; $i ++ )
        array_shift($str);

    $str = implode('', $str); // back to string
}
else
    echo "\$set_strip value not allowed = $set_strip, must be non-negative  and < $strlen";

どちらも次の文字列を返します。defghi

于 2013-01-03T03:17:47.740 に答える