Rubyで特定の文字列を正規表現で抽出し、それを変数に代入したい。もしもマッチする文字列がなかった場合には空も文字列か初期値を代入したい。

まず思いついたコードは

foo = "hoge123hoge"
bar = foo.match(%r{hoge(.+?)hoge})[1] || "default"

これでマッチする場合はうまくいくのだけど、マッチしなかった場合はnilが返ってくるので、それに対して[1]と書くとNoMethodErrorになってしまう😢

うーん、この内容は1行で書きたいよなぁ。。。マッチしなかった場合に返ってくるものを黒魔術的に書き換えるとか?いやいや、そこまでする必要ないよな。

で、少し調べるとマッチしなかった場合は空のhashを与えるようにする方法がヒットした。

参考: [Ruby 正規表現のキャプチャでマッチしなかった時の NoMethodError に対策する](http://qiita.com/Yinaura/items/61f636c9902b8b9cb196)

あーなるほど、これは自分でも分かりやすい。

foo = "hoge123hoge"
bar = (foo.match(%r{hoge(.+?)hoge}) || {})[1] || "default"

初期値を{}の中に書いても同じ動きなので、bar = (foo.match(%r{hoge(.+?)hoge}) || {1: "default"})[1]とかだともう少し短く書けるかな?

その記事のコメントの中にもう少しコンパクトな書き方がある。

foo = "hoge123hoge"
%r{hoge(?<bar>.+?)hoge} =~ foo
puts bar # 123

へー、名前付きキャプチャ便利!けど、これ実はインスタンス変数に代入したかったのだよなぁ。%r{hoge(?<@bar>.+?)hoge}と書くとダメみたい。

ひとまずこのコンパクトな書き方は色々と使えそうなので覚えておこう。