というわけで、その傾向と対策を。
[Perl]UTF8-flagged strings affects regexps with the "i" modifier - use GFx::WebLog;Perlではutf8フラグ付きの文字列に対するuc/lc/"i"正規表現修飾子は非常に遅いのだが,H::F::Liteでは/iを使っているので,試しに/iを使わないようにしてみると,速度が改善した
id:gfxの主張は、以下のようにして確かに確かめられる。
use strict;
use warnings;
use Benchmark qw/cmpthese timethese/;
{
use bytes;
my $str = 'dankogai = 小飼弾';
cmpthese timethese - 1 => {
'//i' => sub { $str =~ /DAN/i },
'/[]/' => sub { $str =~ /[Dd][Aa][Nn]/ },
'/(?i:)/' => sub { $str =~ /(?i:dan)/ },
};
}
{
use utf8;
my $str = 'dankogai = 小飼弾';
cmpthese timethese - 1 => {
'//i' => sub { $str =~ /DAN/i },
'/[]/' => sub { $str =~ /[Dd][Aa][Nn]/ },
'/(?i:)/' => sub { $str =~ /(?i:dan)/ },
};
}
bytes
Rate /(?i:)/ /[]/ //i
/(?i:)/ 2435851/s -- -1% -6%
/[]/ 2453219/s 1% -- -5%
//i 2583577/s 6% 5% --
utf8
//i 445390/s -- -1% -79% /(?i:)/ 449756/s 1% -- -79% /[]/ 2163925/s 386% 381% --
それなら、あらかじめ/dan/iを/[Dd][Aa][Nn]/にしてしまえばいいではないか。というわけで作成したのがこちら。
use strict;
use warnings;
use Benchmark qw/cmpthese timethese/;
sub qri {
my $pat = join '', map { '[' . uc($_) . lc($_) . ']' } split //, shift;
qr($pat);
}
use utf8;
binmode STDOUT => ':utf8';
my $str = 'Спасибо, товарищ GFX!';
my $pat = qri('Спасибо');
print $pat;
cmpthese timethese - 1 => {
'//i' => sub { $str =~ /Спасибо/i },
'/[]/' => sub { $str =~ /[Сс][Пп][Аа][Сс][Ии][Бб][Оо]/ },
'/(?i:)/' => sub { $str =~ /(?i:Спасибо)/ },
'qri+o' => sub { $str =~ /$pat/o },
'qr' => sub { $str =~ /$pat/ },
};
Rate //i /(?i:)/ qr qri+o /[]/
//i 58040/s -- -2% -82% -89% -90%
/(?i:)/ 59077/s 2% -- -82% -89% -89%
qr 330830/s 470% 460% -- -38% -41%
qri+o 530963/s 815% 799% 60% -- -6%
/[]/ 562195/s 869% 852% 70% 6% --
留意点として、precompileされたregexpを使う場合には、//oを指定することがあるが、期待通りの成果と言えるだろう。もちろん、アルファベットだけではなく大文字小文字の区別がある文字であればこのテクニックは全ての文字に使える。
Dan the Regular Expressionist
my $pat = join '', map { uc($_) eq lc($_) ? $_ : '[' . uc($_) . lc($_) . ']' } split //, shift;
がベターかと。