読者です 読者をやめる 読者になる 読者になる

Perl日記

PerlとかRubyとかPHPとかPythonとか

小文字を大文字にする最速の方法は

なんだろうと思って、いろいろやってみた。
MojoとRubyの勉強そっちのけで遊んでしまった。

方法

  • uc()
  • \U
  • tr/a-z/A-Z/
  • 一文字ずつハッシュ

コード

uc()
$text = uc($text);
\U
$text = "\U$text";
tr/a-z/A-Z/
$text =~ tr/a-z/A-Z/;
一文字ずつハッシュ
$_ = $uc{$_} for split //, $text;

なんか恐ろしくハッシュが遅いような気がするけど、uc()もtr///ももしかしたら一文字ずつ同じようなことしてて大差なかったりしないかな。

比較用スクリプト

#!/usr/local/bin/perl
# uc_bench.pl
use strict;
use warnings;
use Benchmark qw(cmpthese timethese);

# ランダム小文字列作成
my @lc = 'a' .. 'z';
sub mk_rand_lc {
  my $len = shift;
  my $rand_lc;
  $rand_lc .= $lc[int(rand(@lc))] for 1 .. $len;
  return $rand_lc;
}

# ハッシュ
my %lc_uc;
$lc_uc{$_} = uc($_) for @lc;

# 比較
my $text = mk_rand_lc(252);
cmpthese(timethese(
  1_000_000 => {
    'uc'   => sub { my $tx = uc($text) },
    '\\U'  => sub { my $tx = "\U$text" },
    'tr'   => sub { (my $tx = $text) =~ tr/a-z/A-Z/ },
    'hash' => sub { my $tx; $tx .= $lc_uc{$_} for split //, $text },
  }
));
__END__

実行

$ ./uc_bench.pl
Benchmark: timing 1000000 iterations of \U, hash, tr, uc...
        \U:  0 wallclock secs ( 0.89 usr +  0.00 sys =  0.89 CPU) @ 1123595.51/s (n=1000000)
      hash: 160 wallclock secs (158.09 usr +  0.20 sys = 158.29 CPU) @ 6317.52/s (n=1000000)
        tr:  1 wallclock secs ( 1.15 usr +  0.00 sys =  1.15 CPU) @ 869565.22/s (n=1000000)
        uc:  0 wallclock secs ( 0.81 usr + -0.01 sys =  0.80 CPU) @ 1250000.00/s (n=1000000)
          Rate   hash     tr     \U     uc
hash    6318/s     --   -99%   -99%   -99%
tr    869565/s 13664%     --   -23%   -30%
\U   1123596/s 17685%    29%     --   -10%
uc   1250000/s 19686%    44%    11%     --

ぎゃあ!
やっぱり小手先対応のハッシュだけぶっちぎりで遅い!
まあsplitが間に挟んじゃってるからなあ、その分余計なのは当然か…。


ではTop3でもう一度。

$ ./uc_bench.pl
Benchmark: timing 1000000 iterations of \U, tr, uc...
        \U:  0 wallclock secs ( 0.85 usr +  0.01 sys =  0.86 CPU) @ 1162790.70/s (n=1000000)
        tr:  2 wallclock secs ( 1.10 usr +  0.00 sys =  1.10 CPU) @ 909090.91/s (n=1000000)
        uc:  1 wallclock secs ( 0.78 usr +  0.00 sys =  0.78 CPU) @ 1282051.28/s (n=1000000)
        Rate   tr   \U   uc
tr  909091/s   -- -22% -29%
\U 1162791/s  28%   --  -9%
uc 1282051/s  41%  10%   --

さすがuc()は格が違った。
ビルトインなだけはある。
何回かやってみたけど、結果はほぼ同じ。

まとめ

小文字を大文字にするにはuc()を使いましょう。
(逆もまた然り)