Skip to content

Instantly share code, notes, and snippets.

@luikore
Last active September 29, 2022 07:50
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save luikore/04fe5c13881b16a33d95 to your computer and use it in GitHub Desktop.
Save luikore/04fe5c13881b16a33d95 to your computer and use it in GitHub Desktop.
To Chinese Number
# http://zh.wikipedia.org/wiki/中文数字
# http://china.younosuke.com/03_013.html
module ChineseNum
extend self
UPPER_ZERO = '零'
LOWER_ZERO = '〇'
UPPER_DIGITS = %w[壹 贰 叁 肆 伍 陆 柒 捌 玖].unshift nil
LOWER_DIGITS = %w[一 二 三 四 五 六 七 八 九].unshift nil
UPPER_MINOR_UNITS = %w[拾 佰 仟].unshift nil
LOWER_MINOR_UNITS = %w[十 百 千].unshift nil
UPPER_MAJOR_UNITS = %w[萬 億].unshift ''
LOWER_MAJOR_UNITS = %w[万 亿].unshift ''
# 两: :all - replace all 二 to 两
# 两: :init - replace all 二 to 两 except the last
# 两: :none - do not replace 二 with 两
# NOTE: "二" 在军事、航空无线电通信或铁路上读作“两”。旧时大写也作弍。作两时用于千、万位或之前及量词之前。但重量“二両”不作“两両”。
def to_cn num, upper: false, upper_zero: upper, 两: :none
# TODO: 小数, 整/正, 角/分, 廿/卅/卌/皕, 古小数:分厘毫丝忽..., 古分数
# TODO: 日本语汉数字
num = num.to_i
j = -1
out = []
cn_digits = upper ? UPPER_DIGITS : LOWER_DIGITS
minor_units = upper ? UPPER_MINOR_UNITS : LOWER_MINOR_UNITS
major_units = upper ? UPPER_MAJOR_UNITS : LOWER_MAJOR_UNITS
zero = upper_zero ? UPPER_ZERO : LOWER_ZERO
num.to_s.chars.map(&:to_i).reverse.each_slice(4) do |digits|
section = digits.zip(minor_units).map do |d, u|
d ||= 0
if d == 0
zero
else
"#{cn_digits[d]}#{u}"
end
end.reverse.join
section.gsub!(/[零〇]+\z/x, '')
j += 1
next if section.empty?
out << major_unit(j, major_units)
out << section
end
res = out.reverse.join.gsub /(?<=\A|[零〇])[零〇]+/, ''
case 两
when :all
res.gsub /[贰二](?![拾十])/, '两'
when :init
res.gsub /[贰二](?![拾十]\z)/, '两'
else
res
end
end
# TODO should generate this?: 一亿一万一千亿
#
# TODO ancient major units
# %w[萬 億 兆 京 垓 秭 穰 沟 涧 正 载 极].unshift ''
# the rate can be 十十变之(*10), 万万变之(*10E4), 数穷则变(**2)
# for SI units standards, 兆=10E6 (十十变之)
# TODO 佛经数字??
def major_unit j, units
(units[1] * (j % 2)) + (units[2] * (j / 2))
end
end
if __FILE__ == $PROGRAM_NAME
print "10000 -> "; puts ChineseNum.to_cn 10000
print "2000 -> "; puts ChineseNum.to_cn 2000, upper: true
print "1001_0003 -> "; puts ChineseNum.to_cn 1001_0003, upper: true
print "123_0929 -> "; puts ChineseNum.to_cn 123_0209, upper_zero: false, 两: :all
print "1000_0000 -> "; puts ChineseNum.to_cn 1000_0000
print "10e60 + 2 -> "; puts ChineseNum.to_cn 10 ** 60 + 2, upper_zero: true
print "10e8 -> "; puts ChineseNum.to_cn 10 ** 10
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment