文字列の中に文字列の中の文字がすべて存在する?
ある文字列 a の中に別のある文字列 b を構成する文字がすべて存在するかを調べる。
もう少し条件を加えると、b の文字の順番を保っていること。例えば、こんな感じ。
# OK a = 'xyz123' b = 'xz3' # NG a = 'xyz123' b = '3zx' # 順番が合っていない # NG a = 'xyz123' b = 'xzz3' # 'z' が足りない。一度マッチした文字は使えない。
こういう機能が必要になった。
調査
で、2 通りの実装を思いついたのだが、どちらが速いかわからなかったので試してみた。
一つは正規表現を使う方法で、もう一つは String.index を使う方法。
コード
require 'benchmark' search_word = 'aiueo' loop = 10000 subjects = Array.new(loop) {|i| i.to_s + ('a'..'z').to_a.to_s * 2} Benchmark.bm do |x| # 正規表現版 # "aiueo" => /a.*i.*u.*e.*o/ x.report do search_reg = Regexp.new( search_word.split(//u). map{|s| Regexp.escape(s, 'u').to_s }. join('.*') ) subjects.each do |subject| index = search_reg =~ subject end end # index版 x.report do subjects.each do |subject| index = nil head = 0 search_word.size.times do |i| index = subject[head, subject.size].index(search_word[i, 1]) break unless index head += index + 1 end end end end
結果
上段が正規表現版、下段が String.index版。search_word を 4 パターンと、loopの数を 2 パターン試してみた。
# search_word = 'aiueo' => マッチする, loop = 10000 user system total real 0.080000 0.010000 0.090000 ( 0.088257) 0.180000 0.020000 0.200000 ( 0.188585) # search_word = 'Xaiueo' => マッチしない, loop = 10000 user system total real 0.010000 0.000000 0.010000 ( 0.022401) 0.050000 0.020000 0.070000 ( 0.073230) # search_word = 'aiuXeo' => マッチしない, loop = 10000 user system total real 0.090000 0.000000 0.090000 ( 0.097294) 0.150000 0.030000 0.180000 ( 0.170762) # search_word = 'aiueoX' => マッチしない, loop = 10000 user system total real 0.100000 0.020000 0.120000 ( 0.116577) 0.190000 0.040000 0.230000 ( 0.236802) # search_word = 'aiueo' => マッチする, loop = 1 user system total real 0.000000 0.000000 0.000000 ( 0.000296) 0.000000 0.000000 0.000000 ( 0.000082)