Edited at

[Ruby] 整数に万億兆などの単位をつける


概要

n 番煎じです。Rubyで大きい数字に対して億万などの単位をつける方法 という記事を拝見し、自分ならどう書くかを考えてみました。

例えば 1,234,567,890 を 12億3456万7890 に変換したいです。"千" は付けません。


方法


コード

module ToJ

UNITS = %w[万 億 兆 京 垓 𥝱 穣 溝 澗 正 載 極 恒河沙 阿僧祇 那由多 不可思議 無量大数].freeze

refine Integer do
def to_j
sign = negative? ? '-' : ''
splitted = abs.to_s.reverse.each_char.each_slice(4).map(&:reverse).map(&:join).map(&:to_i)
j = splitted.zip([nil, *UNITS]).reject { |n, _| n.zero? }.reverse.join
j.empty? ? '0' : sign + j
end
end
end


実行例

using ToJ

1234567890.to_j #=> "12億3456万7890"

# マイナスを再現する。
-1234567890.to_j #=> "-12億3456万7890"

# 余計な 0 は省く。
100000010000000000.to_j #=> "10京100億"

# 0 は "0"。
0.to_j #=> "0"


解説

まず、整数 n を 4 桁ずつに分割した配列にします。このとき、次の処理に備えて配列を逆順にしておきます。

n = 10023456700000890

splitted = n.abs.to_s.reverse.each_char.each_slice(4).map(&:reverse).map(&:join).map(&:to_i)
#=> [890, 0, 4567, 23, 1]

# ちなみにこんな書き方もできる。
splitted = n.abs.to_s.reverse.gsub(/\d{4}/, '\0 ').reverse.split(' ').reverse.map(&:to_i)
#=> [890, 0, 4567, 23, 1]

そして単位の配列と組み合わせます。

splitted.zip([nil, *UNITS])

#=> [[890, nil], [0, "万"], [4567, "億"], [23, "兆"], [1, "京"]]

ここで 0 の桁は省きます。

splitted.zip([nil, *UNITS]).reject { |n, _| n.zero? }

#=> [[890, nil], [4567, "億"], [23, "兆"], [1, "京"]]

最後に配列を結合して文字列にし、並び順を戻せば完成です :tada:

splitted.zip([nil, *UNITS]).reject { |n, _| n.zero? }.reverse.join

#=> "1京23兆4567億890"

なお 0 の場合は上記の結果が "" になるので、その場合は "0" を返すようにします。


参考