Rubyで「正規表現でマッチした部分を抽出する」を書いたのだが、なんかしょぼかったので復習

Rubyで「文字列から正規表現にマッチする部分だけぶっこ抜く」ってのをやろうとしてこんな風に書いたのだけど、もっとシンプルに書けるはずだったので復習。

str = 'http://instagram.com/p/hoge/' #hogeを抜き出したい
m = str.match(/http:\/\/instagram.com\/p\/(.+?)\//)
id = m[1]
puts id

まず、http:\/\/みたいにエスケープしまくるのが面倒。%rを使えば完結に書けた。%rは直後に来る文字を正規表現のデリミタとする。今回の例だと/が何度も出てくるので、/以外の文字をデリミタにすれば、何度もエスケープする必要がなくなる。

%r{http://instagram.com/p/(.+?)/}

デリミタにする文字は何でもよい。なので、これも等価。

%r!http://instagram.com/p/(.+?)/!

次にm=の部分。変数に代入する必要はない。str.match(%r{http://instagram.com/p/(.+?)/})はマッチするとMatchDataオブジェクトを返す。[]はMatchDataオブジェクトのメソッドなので、普通に繋げて書ける。結局、最初のコードは以下のように書ける。

str = 'http://instagram.com/p/hoge/'
id = str.match(%r{http://instagram.com/p/(.+?)/})[1]
puts id
# p (str.match(%r{http://instagram.com/p/(.+?)/})).class => MatchData

ちなみに、上記ではmatchメソッドを使ったが、=~演算子を使っても書ける。ただし、その場合マッチした結果返ってくる値はMatchDataオブジェクトではなく、マッチした部分の位置になる。MatchDataオブジェクトはどこにセットされているかというと、$~という変数にセットされている。

str = 'http://instagram.com/p/hoge/'
str =~ %r{http://instagram.com/p/(.+?)/}
id = $~[1]
puts id
# p (str =~ %r{http://instagram.com/p/(.+?)/}) => 0
# p $~.class => MatchData

正規表現苦手意識克服したい