正規表現のパターンを変数に入れる

いつもいつも「あれ?どうやるんだっけ?」と悩んでググったり、irbで試したりしてしまうので、ここに書いておくと忘れないんじゃないかと。

いろいろなケース

irb> ptn = '^http://.+?/'        ← URIのルートを取ってくるパターン
 => "^http://.+?/"
irb> uri = "http://2.5-55.jp/items/etc" ← テスト用URI
 => "http://2.5-55.jp/items/etc"

まず、ノーマルなケース。変数を入れるのについつい "#{}"とダブルコートでくくってしまいそうになりますが、そうするとダブルコート込みのパターン認識になってしまいます。

irb> uri.scan(/#{ptn}/)  ← 正しい
 => ["http://2.5-55.jp/"]
irb> uri.scan(%r|#{ptn}|) ← 正しい
 => ["http://2.5-55.jp/"]
irb> uri.scan(/"#{ptn}"/) ← 間違い
 => []

パターンは一度変数に入れると「/」はエスケープしなくてもいいみたいですね。「/」をエスケープしてみても同じ結果です。

irb> ptn = '^http:\/\/.+?\/' ← /エスケープ
 => "^http:\\/\\/.+?\\/"
irb> uri.scan(/#{ptn}/)    ← OK
 => ["http://2.5-55.jp/"]
irb> uri.scan(%r|#{ptn}|)   ← OK
 => ["http://2.5-55.jp/"]

パターンを表す「/」まで変数に入れてみたらどうなるでしょうか。ダメですね。

irb> ptn = '/^http:\/\/.+?\//' ← /を追加
 => "/^http:\\/\\/.+?\\//"
irb> uri.scan(/#{ptn}/)     ← NG
 => 
irb> uri.scan(%r|#{ptn}|)    ← NG
 => 

では、「%r」を変数に入れたらどうでしょう。配列の先頭だけみると正しい結果が返ってきています。ただ、返ってきてる結果をみるとちょっと嫌な感じなので、やらないほうが無難ですね。

irb> ptn = '%r|^http:\/\/.+?\/|' ← %r||を追加
 => "%r|^http:\\/\\/.+?\\/|"
irb> uri.scan(/#{ptn}/)
 => ["http://2.5-55.jp/", "", "", "", "", "", "", "", "", "", ""]
irb> uri.scan(%r|#{ptn}|)
 => ["http://2.5-55.jp/", "", "", "", "", "", "", "", "", "", ""]
irb>