Ruby手習い(MatchDataクラス)

アウトプットのネタに困ったらこれ!?Ruby初心者向けのプログラミング問題を集めてみた(全10問) - give IT a try

上記記事の値札分割問題。

自分で書いたコード

def split_price(price_text)
  match = price_text&.match(/[\d\s0-9.,-]+|価格未定/)
  num = match ? match[0] : ""
  unit = price_text ? price_text[num.length..-1] : ""
  [num, unit]
end

数値部分だけみつけて、全体から数値部分をとりだした。

他の回答例

def split_price(price_text)
  regex = /([^万円]+)(万?円)/
  regex.match(price_text).to_a[1..2] || [price_text.to_s, '']
end

「数値部分だけとりだし、全体から数値部分を削除して単位部分を得る」ではなく、正規表現の中で()により数字部分と単位部分をまとめて取得するのがきれいだ。

def split_price(price_text)
  price_text.to_s.match(/([^万円]*)(.*)/)[1..2]
end

なるほど!*をつかうことによって必ずマッチする(少なくとも""がマッチする)ため、matchの戻り値がnilの場合を別に定めなくてすむ。

学んだこと

  • String#match(regexp)Regexp#match(string)の戻り値はMatchDataクラス。
  • MatchData[n]はn=0で$&(マッチした最初のの文字列全体)を返し、n>=1で${n}(マッチした最初の文字列のうち、正規表現内の()により得られたn番目の部分文字列)を返す。
    • マッチしなければnilを返す。
  • MatchData#to_a[$&, $1, $2, $3...]を返す。

参考:class MatchData (Ruby 2.6.0)