rescue
節があるから複数行だ、というご指摘もあるでしょうが、そこはご容赦を。
イディオム
マッチしない場合には空文字列を返すことにします。
begin
'%d:%d' % time_str.match(/(\d\d)時(\d\d)分/).captures
rescue
""
end
begin '%d:%d' % time_str.match(/(\d\d)時(\d\d)分/).captures rescue "" end
(コメント反映追記1)後置
rescue
文なら読みやすさに問題なし'%d:%d' % time_str.match(/(\d\d)時(\d\d)分/).captures rescue ""
(コメント反映追記2)時分を
Array#join
で繋げてしまうtime_str.match(/(\d{2})時(\d{2})分/).captures.join(":")
(コメント反映追記3)対象文字列の必要部分が数字2文字×2なので、数字2文字を
String#scan
で取得して配列化、それをArray#join
で繋げるtime_str.scan(/\d{2}/).join(':')
解説
部分マッチ抜き出し
String#match
はMatchData
オブジェクトを返します。
MatchData
はマッチ全体$&
及び部分マッチ($1
, $2
, …)を含みます。このため単純にMatchData#to_a
を使うと
"12時34分".match(/(\d\d)時(\d\d)分/).to_a
=> ["12時34分", "12", "34"]
のようにマッチ全体も含んでいます。
ここで使いたいのは部分マッチ情報だけなのでMatchData#captures
を使います。
"12時34分".match(/(\d\d)時(\d\d)分/).captures
=> ["12", "34"]
ただし、部分マッチがなかった場合にMatchData#captures
はnil
を返すので、その対策としてrescue
しています。
フォーマット
MatchData#captures
で得られた配列をString#%
でフォーマットします。
'%d:%d' % "12時34分".match(/(\d\d)時(\d\d)分/).captures
=> "12:34"
私はString#%
の書き方に慣れていますが、違和感を感じる場合にはKernel.#format
やKernel.#sprintf
なども使えます。ただし、Kernel.#format
やKernel.#sprintf
の第2引数は配列を受けられないのでsplat(*
)で開く必要があります。
format('%d:%d', *("12時34分".match(/(\d\d)時(\d\d)分/).captures))
=> "12:34"