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"
_
それは逆です。
別のオプションは、位置を0に設定して rindex
を使用することです。これは、「位置<= 0から始まる$ strの$ substrのインデックスを取得する」、つまり$ substr $ strのプレフィックスです:
> rindex "abc", "a", 0
0
> rindex "abc", "b", 0
-1
これは本当に重要ですか?いくつかのベンチマークを実行しましたが、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です。
index
とsubstr
のソリューションはまだ非常に高速でした。 index
は成功/失敗に対して11.83μs/11.86μsで、substr
は4.09μs/4.15μsでした。コードを別の関数に移動すると、約0.222±0.05μsが追加されました。
ベンチマークコードは次の場所にあります: http://codepaste.net/2k1y8e
@Stephaneのデータの特性はわかりませんが、私のアドバイスは有効です。