Perl FAQエントリ文字列の最初/最後から空白を取り除くにはどうすればよいですか?使用すると述べています
s/^\s+|\s+$//g;
2つのステップでそれを行うよりも遅いです:
s/^\s+//;
s/\s+$//;
この結合されたステートメントが、(任意の入力文字列に対して)個別のステートメントよりも著しく遅いのはなぜですか?
Perl FAQエントリ文字列の最初/最後から空白を取り除くにはどうすればよいですか?使用すると述べています
s/^\s+|\s+$//g;
2つのステップでそれを行うよりも遅いです:
s/^\s+//;
s/\s+$//;
この結合されたステートメントが、(任意の入力文字列に対して)個別のステートメントよりも著しく遅いのはなぜですか?
Perl 正規表現ランタイムは、「浮動」部分文字列ではなく、「固定」または「アンカー」部分文字列を使用する場合にはるかに高速に実行されます。ソース文字列の特定の場所にロックできる場合、部分文字列は固定されます。「^」と「$」の両方がそのアンカーを提供します。ただし、代替 '|' を使用すると、コンパイラは選択肢を固定として認識しないため、最適化されていないコードを使用して文字列全体をスキャンします。そして、プロセスの最後に、固定文字列を 2 回検索する方が、浮動文字列を 1 回検索するよりもはるかに高速です。関連して、perl の regcomp.c を読むと盲目になります。
更新: ここにいくつかの追加の詳細があります。デバッグ サポート付きでコンパイルした場合は、'-Dr' フラグを指定して perl を実行できます。これにより、正規表現コンパイル データがダンプされます。得られるものは次のとおりです。
~# debugperl -Dr -e 's/^\s+//g'
Compiling REx `^\s+'
size 4 Got 36 bytes for offset annotations.
first at 2
synthetic stclass "ANYOF[\11\12\14\15 {unicode_all}]".
1: BOL(2)
2: PLUS(4)
3: SPACE(0)
4: END(0)
stclass "ANYOF[\11\12\14\15 {unicode_all}]" anchored(BOL) minlen 1
# debugperl -Dr -e 's/^\s+|\s+$//g'
Compiling REx `^\s+|\s+$'
size 9 Got 76 bytes for offset annotations.
1: BRANCH(5)
2: BOL(3)
3: PLUS(9)
4: SPACE(0)
5: BRANCH(9)
6: PLUS(8)
7: SPACE(0)
8: EOL(9)
9: END(0)
minlen 1
最初のダンプの「アンカー」という単語に注意してください。
他の回答は、完全に固定された正規表現により、エンジンが検索プロセスを最適化し、最初または最後、あるいは文字列だけに焦点を当てることができることを示しています。さまざまな長さのストリングを使用して2つのアプローチの速度差を比較することにより、この最適化の効果を確認できるようです。文字列が長くなるにつれて、「フローティング」正規表現(交互を使用)はますます苦しみます。
use strict;
use warnings;
use Benchmark qw(cmpthese);
my $ws = " \t\t\n";
for my $sz (1, 10, 100, 1000){
my $str = $ws . ('Z' x $sz) . $ws;
cmpthese(-2, {
"alt_$sz" => sub { $_ = $str; s/^\s+|\s+$//g },
"sep_$sz" => sub { $_ = $str; s/^\s+//; s/\s+$// },
});
}
Rate alt_1 sep_1
alt_1 870578/s -- -16%
sep_1 1032017/s 19% --
Rate alt_10 sep_10
alt_10 384391/s -- -62%
sep_10 1010017/s 163% --
Rate alt_100 sep_100
alt_100 61179/s -- -92%
sep_100 806840/s 1219% --
Rate alt_1000 sep_1000
alt_1000 6612/s -- -97%
sep_1000 261102/s 3849% --
2 つの方法は論理的に同等であるため、評価のパフォーマンスが異なる固有の理由はありません。ただし、実際には、一部のエンジンは、より複雑な正規表現の最適化を見つけることができません。
この場合、結合された正規表現は全体としてアンカーされていないため、文字列内の任意のポイントで一致する可能性がありますが、^\s+
は先頭でアンカーされているため、簡単に一致\s+$
し、末尾でアンカーされ、最後から後方に向かって各文字の単一文字クラス - 十分に最適化されたエンジンはその事実を認識し、逆に一致するため、入力の逆の一致と同じくらい簡単^\s+
になります。
これが実際に当てはまる場合は、正規表現エンジンが組み合わせた正規表現よりも個々の正規表現をより適切に最適化できるためです。
「著しく遅い」とはどういう意味ですか?