LoginSignup
5
5

More than 5 years have passed since last update.

文字列"12時34分"を"12:34"へ一行で変換

Last updated at Posted at 2014-06-03

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#matchMatchDataオブジェクトを返します。
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#capturesnilを返すので、その対策としてrescueしています。

フォーマット

MatchData#capturesで得られた配列をString#%でフォーマットします。

'%d:%d' % "12時34分".match(/(\d\d)時(\d\d)分/).captures
=> "12:34"

私はString#%の書き方に慣れていますが、違和感を感じる場合にはKernel.#formatKernel.#sprintfなども使えます。ただし、Kernel.#formatKernel.#sprintfの第2引数は配列を受けられないのでsplat(*)で開く必要があります。

format('%d:%d', *("12時34分".match(/(\d\d)時(\d\d)分/).captures))
=> "12:34"

参考リンク(るりま)

5
5
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5