Ruby 3.2 アドベントカレンダーの12日目の記事です。
Regexp
Regexp.new に文字列でオプション指定可能
Ruby の正規表現リテラルは /hoge/im
みたいに後ろにオプションをつけられるんだけど、Regexp.new
の場合は、
Regexp.new('hoge', Regexp::IGNORECASE|Regexp::MULTILINE) #=> /hoge/mi
みたいに書かないといけなかった。めんどくさい。
文字列で指定して、
Regexp.new('hoge', 'i') #=> /hoge/i
お、できるじゃん! って思うかもしれないけどこれは罠で、第2引数が数値以外で真の場合は i
になる。
Regexp.new('hoge', 'm') #=> /hoge/i
Ruby 3.2 では文字列でも指定できるようになった。
Regexp.new('hoge', 'im') #=> /hoge/mi
便利。
Regexp.timeout= 追加
Feature #17837: Add support for Regexp timeouts - Ruby master - Ruby Issue Tracking System
ReDoS 対策として、正規表現のパターンマッチをタイムアウトさせることができるようになった。
Regexp.timeout = 0.000001 "a"*1000+"X" =~ /\A(a+)+\z/ #=> regexp match timeout (Regexp::TimeoutError)
正規表現のマッチングアルゴリズムの改善
上の正規表現のマッチングは Ruby 3.2 だとタイムアウトを設定しなくても一瞬で終わるけど、Ruby 3.1 だと終わらない。
"a"*30+"X" =~ /\A(a+)+\z/
これでも 13秒くらいかかる。Ruby 3.2 でアルゴリズムが変更されt大幅に改善されたらしい。
NEWS.md には書いてないけど、3.2.0 RC 1 リリースのお知らせには書いてあった。