📝
【Ruby】正規表現のMatchDataをパターンマッチで使う
RegExp#match
の戻り値であるMatchData
はパターンマッチに対応しており、キャプチャしたグループの文字列を直接取り出すのに使える。if
の条件として自然に使えて、なかなかいい感じだと思う。
if /(\d{4})-(\d{2})-(\d{2})/.match("2024-09-01") in year, month, day
puts year #=> 2024
puts month #=> 09
puts day #=> 01
end
キャプチャが1つしかない場合はarray_patternであることを明示する[]
が必要になる。
if /(\d+)/.match("aaa999aa") in [number]
puts number #=> 999
end
名前付きキャプチャも使える。
if /\$(?<dollars>\d+)\.(?<cents>\d+)/.match("$3.67") in dollars:, cents:
puts dollars #=> 3
puts cents #=> 67
end
ただし正規表現内にキャプチャがない場合はうまく動作しない。正規表現マッチが失敗した場合の戻り値nil
が常にパターンにマッチしてしまうので、成功・失敗を判定できない。
#これはダメ
if /\d+/.match("aaa999aa") in n
p n #=> #<MatchData "999">
end
if /\d+/.match("aaabb") in n
p n #=> nil
end
パターンマッチで、正規表現マッチした文字列全体を簡単に取り出す方法は無い……と思う。
無理矢理な方法はいくつか考えられるが……普通に変数代入使うか、Regexp.last_match
経由の方がわかりやすいかな。
#案1: 配列化する。#values_atでも可
if /\d+/.match("aaa999aa").to_a in [number]
puts number #=> 999
end
#案2: 文字列化する。safe navigation operator必須
if /\d+/.match("aaa999aa")&.to_s in String => number
puts number #=> 999
end
#案3: 素直にMatchDataを取り出す
if /\d+/.match("aaa999aa") in MatchData => m
puts m.to_s #=> 999
end
Discussion