💎

Ruby 3.2 - Regexp

2022/12/12に公開

Ruby 3.2 アドベントカレンダーの12日目の記事です。

https://qiita.com/advent-calendar/2022/ruby32


Regexp

Regexp.new に文字列でオプション指定可能

Feature #18788: Support passing Regexp options as String to Regexp.new - Ruby master - Ruby Issue Tracking System

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)

正規表現のマッチングアルゴリズムの改善

Feature #19104: Introduce the cache-based optimization for Regexp matching - Ruby master - Ruby Issue Tracking System

上の正規表現のマッチングは Ruby 3.2 だとタイムアウトを設定しなくても一瞬で終わるけど、Ruby 3.1 だと終わらない。

"a"*30+"X" =~ /\A(a+)+\z/

これでも 13秒くらいかかる。Ruby 3.2 でアルゴリズムが変更されt大幅に改善されたらしい。

NEWS.md には書いてないけど、3.2.0 RC 1 リリースのお知らせには書いてあった。

Discussion