はじめに
競技プログラミングの問題いくつか解きました。
遅いといわれる Ruby でもっと高速化するにはどうしたらよいかとちょっと疑問が出たので検証してみました。
第1弾は「高速な正規表現はどう書けばよいのか?」です
Rubyの環境構築は以前の記事 「docker compose で Ruby 環境の構築」を参照ください
正規表現って?
ある文字列が特定のパターンに一致しているかまたはその記述方法[2]のことです。
例えば「〇〇市の住所であるか」「入力したメアドは正しい構造か」等を確認する為に使われたりします。
どいつが速いか選手権
エントリーコード
- String.=~
- String.match
- Regexp.=~
- Regexp.match
速度検証コード
検証コード[2]でベンチマークとってみます。
require 'benchmark'
include Benchmark
line = ARGV[0]
Benchmark.benchmark(CAPTION, 7, FORMAT) do |x|
x.report("Regexp.=~:"){ /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/ =~ line }
x.report("Regexp.match:"){ /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/.match(line) }
x.report("String.=~:"){ line =~ /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/ }
x.report("String.match:"){ line.match(/\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/) }
end
root@6615b1eae437:/usr/src/src# ruby regular_test.rb test@example.com
user system total real
Regexp.=~: 0.000007 0.000002 0.000009 ( 0.000005)
Regexp.match: 0.000006 0.000002 0.000008 ( 0.000006)
String.=~: 0.000002 0.000001 0.000003 ( 0.000002)
String.match: 0.000006 0.000001 0.000007 ( 0.000006)
今回は user で Ruby コードの処理時間のみを比較します。
以外だったんですが、 String.=~ とその他で違いが出てしました。
型ごとに分かれるかと予想していました。
しかし、String.match[3] を読むと Regexp#match と同じと記述があったので計測結果は妥当なんでしょうね。
処理時間が極端に遅いわけではないので、個人的にはコードの読みやすさとか考えたら String.match がよさそうかなと思います。
まとめ
速度優先するなら String.=~。(好みだが)読みやすさなら String.match がよさそう
参考
[1] Ruby 3.1 リファレンスマニュアル 正規表現, https://docs.ruby-lang.org/ja/latest/doc/spec=2fregexp.html
[2] https://github.com/turkey136/ruby-example/commit/7bd2a8e818bebdac362c97728ce28bfc9995e465
[3] String.match, https://docs.ruby-lang.org/ja/latest/class/String.html#I_MATCH
コメント