すがブロ

sugamasaoのhatenablogだよ

=~ と scan のパフォーマンスについて

以前も調べたのだけど、ちゃんとしたロジックで再検証してみる

以前、scan と正規表現のグループ化 - @sugamasao.blog.title # => ”コードで世界を変えたい” でも調べていて、scan の方が遅い事がわかったのだけど、もうちょっとまともなロジックで再検討してみる。
下記は MIME エンコード*1された文字列から文字コードエンコード方式と、大本の文字列を抜き出す正規表現
それらを 10000 回繰り返してベンチマークを取ってみた。
ソースはこちら

  1 require 'benchmark'
  2 
  3 n = 10000
  4 
  5 def reg_test(str)
  6   if str =~ /.*?=\?(.+?)\?(.)\?(.+?)\?=/
  7     #puts $1
  8     #puts $2
  9     #puts $3
 10   end
 11 end
 12 
 13 def scan_test(str)
 14   str.scan( /.*?=\?(.+?)\?(.)\?(.+?)\?=/) do |s|
 15     #puts s[0]
 16     #puts s[1]
 17     #puts s[2]
 18   end
 19 end
 20 
 21 Benchmark.bm do |b|
 22   b.report("reg_test") { n.times { reg_test("=?UTF-8?B?44GC44GC44GC44GC44GC44GC?=") } }  
 23   b.report("scan_test") { n.times { scan_test("=?UTF-8?B?44GC44GC44GC44GC44GC44GC?=") } }
 24 end

ちなみに、コメントアウトしてある部分を外すと、以下のように出力される。
一番上から、文字コードエンコード方式(今回は BASE64)、エンコードされた文字列の順。

UTF-8
B
44GC44GC44GC44GC44GC44GC

測定結果

:! ruby test.rb
      user     system      total        real
reg_test  0.050000   0.000000   0.050000 (  0.052958)
scan_test  0.070000   0.000000   0.070000 (  0.070909)

結論

やっぱり scan の方が時間掛かる。この手のパース処理って他に高速化できる手段はあるのだろうか。やっぱ racc 使えって感じ?

*1:日本語のメール件名に使われたりするヤツね