正規表現オブジェクトの作り方と注意点

Ruby正規表現オブジェクトを作る方法は以下の三通り。

  1. /pattern/option
  2. %r{pattern}option
  3. Regexp.new('pattern', option)

一番利用頻度が高いのが/pattern/で、この場合patternには式展開を含める事ができる。

/hoge#{"foo"}/
# => /hogefoo/

ただし、optionには式展開を含める事ができない(正確にはできるが、無視される)。これはコンパイルエラーにもならないので注意が必要。

/hoge#{"foo"}/#{"ni"}
# => /hogefoo/ #式展開でくっつけたoption値が無視されている。

%r記法でも同様である。


その為、optionを動的にしたい場合はRegexp.newメソッドを使用する。
…と思っていたのだが、そうでもないらしい。

Regexp.new("hoge", "i")
# => /hoge/i

Regexp.new("hoge", "o")
# => /hoge/i

どんな値を入れても何故かignore caseがオプションになってしまう。


Regexpのrdocを見て謎が解明。

第二引数が Fixnum であった場合、その値は

Regexp::IGNORECASE
Regexp::MULTILINE
Regexp::EXTENDED
論理和でなければなりません。

第二引数が Fixnum 以外であれば真偽値の指定として見なされ、真 (nil, false 以外)であれば Regexp::IGNORECASE の指定と同じになります。

http://www.ruby-lang.org/ja/man/?cmd=view;name=Regexp

わざわざ論理和とか計算したり長い定数名を書くらいならcaseで分けた方が早いと思う…。
そもそもoptionに式展開を含めたいと考えたのは文字コードを動的に変えたいからだった。
引き続きRegexpのrdocを読んで見ると以下のような記述を発見。

第三引数が与えられた時には、$KCODE の値にかかわらず、指定された文字コードでマッチを行います。文字コードは $KCODE への代入と同様に文字列引数の最初の一文字で決定されます。

http://www.ruby-lang.org/ja/man/?cmd=view;name=Regexp


と言うわけで以下のように使うと今回の目的は達成できる。

charset = "s"
Regexp.new("hoge", nil, charset)
# => /hoge/s

charset = "u"
Regexp.new("hoge", Regexp::MULTILINE , charset)
# => /hoge/mu