web-dev-qa-db-ja.com

perlで$ stringが$ needleで始まるかどうかを確認する最も効率的な方法

Perlの2つの文字列変数_$string_および_$needle_が与えられた場合、_$string_が_$needle_で始まるかどうかを確認する最も効率的な方法は何ですか。

  • _$string =~ /^\Q$needle\E/_は、私が考えることができる最も近い一致であり、必要なことを行いますが、私が試したソリューションの中で最も効率的ではありません(はるかに)。
  • index($string, $needle) == 0は動作し、_$string_および_$needle_の一部の値に対して比較的効率的ですが、他の位置で針を不必要に検索します(開始時に見つからない場合)。
  • substr($string, 0, length($needle)) eq $needleは非常にシンプルで効率的である必要がありますが、私の少数のテストのほとんどでは、以前のテストほど効率的ではありません。

私が知らないPerlでそれを行う標準的な方法や、上記のソリューションのいずれかを最適化する方法はありますか?

(私の特定のユースケースでは、_$string_と_$needle_は実行ごとに異なるため、正規表現のプリコンパイルはオプションではありません)。


特定のソリューションのパフォーマンスを測定する方法の例(ここではPOSIX shから):

_string='somewhat not so longish string' needle='somew'
time Perl -e '
  ($n,$string,$needle) = @ARGV;
  for ($i=0;$i<$n;$i++) {

    index($string, $needle) == 0

  }' 10000000 "$string" "$needle"
_

これらの値を使用すると、index()は、Perl 5.14.2を使用するこのシステムでsubstr()+eqよりも優れたパフォーマンスを発揮しますが、次のようになります。

_string="aaaaabaaaaabaaaaabaaaaabaaaaabaaaaab" needle="aaaaaa"
_

それは逆です。

22

別のオプションは、位置を0に設定して rindex を使用することです。これは、「位置<= 0から始まる$ strの$ substrのインデックスを取得する」、つまり$ substr $ strのプレフィックスです:

> rindex "abc", "a", 0
0
> rindex "abc", "b", 0
-1
5
Gregory Kalabin

これは本当に重要ですか?いくつかのベンチマークを実行しましたが、indexメソッドは1反復あたり平均0.68マイクロ秒でした。正規表現法1.14μs; substrメソッド0.16μs。私の最悪のシナリオ(等しい2250文字の文字列)でさえ、indexは2.4μs、regexは5.7μs、substrは0.5μsかかりました。

私のアドバイスは、ライブラリルーチンを記述することです。

sub begins_with
{
    return substr($_[0], 0, length($_[1])) eq $_[1];
}

最適化の取り組みを他の場所に集中させます。

更新:上記の「最悪の」シナリオに対する批判に基づいて、ランダムに生成された20,000文字の文字列で新しいベンチマークセットを実行し、それ自体と最後のバイトのみが異なる文字列と比較しました。

このような長い文字列の場合、正規表現のソリューションは最悪でした(20,000文字の正規表現は地獄です):成功した場合は105μs、失敗した場合は100μsです。

indexsubstrのソリューションはまだ非常に高速でした。 indexは成功/失敗に対して11.83μs/11.86μsで、substrは4.09μs/4.15μsでした。コードを別の関数に移動すると、約0.222±0.05μsが追加されました。

ベンチマークコードは次の場所にあります: http://codepaste.net/2k1y8e

@Stephaneのデータの特性はわかりませんが、私のアドバイスは有効です。

19
Sue D. Nymme