#比如: 138 <=> 一百三十八
$KCODE = 'u'
require 'jcode'
require 'iconv'
$cn_nums = %w{零 一 二 三 四 五 六 七 八 九}
$cn_decs = %w{十 百 千 万 十 百 千 亿}
$conv = Iconv.new('gbk', 'utf-8')
$cn_nums_map = {
'〇' => 0,
'一' => 1,
'二' => 2,
'三' => 3,
'四' => 4,
'五' => 5,
'六' => 6,
'七' => 7,
'八' => 8,
'九' => 9,
'零' => 0,
'壹' => 1,
'贰' => 2,
'叁' => 3,
'肆' => 4,
'伍' => 5,
'陆' => 6,
'柒' => 7,
'捌' => 8,
'玖' => 9,
'貮' => 2,
'两' => 2,
}
$cn_decs_map = {
'个' => 1,
'十' => 10,
'拾' => 10,
'百' => 100,
'佰' => 100,
'千' => 1000,
'仟' => 1000,
'万' => 10000,
'萬' => 10000,
'亿' => 100000000,
'億' => 100000000,
'兆' => 1000000000000,
}
def uputs(str)
puts $conv.iconv(str)
end
class NumCnConv
private
def digit2cn(d)
$cn_nums[d - '0'[0]]
end
def is_all_zero(str)
return str == ('0'*str.size)
end
public
def num2cn(num)
str = num.to_s
# print str + ":"
result = []
str = str.reverse
zero_count = 0 #zero_count after last non-zero digit
index = 0 #the index for the numbers
first_zero = true #don't need to insert 零 for numbers like /[1-9]+0+/
str_wan_yi = nil #insert 万 & 亿 when needed
while index < str.size do #3 0423 4829
d = str[index]
#puts "index = #{index} (#{d.chr})"
if (d - '0'[0] > 0)
if zero_count > 0
zero_count = 0
result << digit2cn('0'[0]) if !first_zero
if str_wan_yi != nil
result << str_wan_yi
str_wan_yi = nil
end
end
result << $cn_decs[(index - 1) % ($cn_decs.size)] if index > 0
result << digit2cn(d)
first_zero = false
else
if (index > 0 && (index % 4) == 0 && !is_all_zero(str[index, 4]) )
str_wan_yi = $cn_decs[(index - 1) % ($cn_decs.size)]
end
zero_count += 1
end
index += 1
end
if zero_count > 0
zero_count = 0
result << digit2cn('0'[0])
end
result = result.reverse
res = result.join
if res =~ /^一十/
res = res['一'.size, res.size - '一'.size]
end
# uputs res
return res
end
def cn2num(str)
#remove 零
num_str = ''
last = nil
str.scan(/./u) do |c|
if (!$cn_nums_map[c] && !$cn_decs_map[c])
uputs "#{str} 是个错误的数字串"
return nil
end
num_str += c if c != '零'
last = c
end
if num_str =~ /^十/
num_str = '一' + num_str
end
sums = []
temp_sum = 0
last_num = 0
num_str.scan(/./u) do |ch|
if num = $cn_nums_map[ch]
last_num = num
else
dec = $cn_decs_map[ch]
if dec < 10000
temp_sum += last_num * dec
else
#find back for the one that exceeds current dec
sums.each_with_index do |x, i|
if x < dec * 10 #10 is here for situation like 两亿亿
sums[i] = x * dec
else
break
end
end
temp_sum += last_num
sums << temp_sum * dec
temp_sum = 0
end
last_num = 0
end
end
sums << temp_sum + last_num
sum = 0
sums.each do |x|
sum += x
end
return sum
end
end
#$cn_nums_map.each do |key, value|
#uputs key + "=>" + value.to_s
#end
#myconv = NumCnConv.new
#puts myconv.cn2num('两亿亿')
#-------------------------------------------
#测试程序
require 'test\unit'
$td_map = {
#1 digit 个
'零' => 0,
'一' => 1,
'二' => 2,
'三' => 3,
'四' => 4,
'五' => 5,
'六' => 6,
'七' => 7,
'八' => 8,
'九' => 9,
#2 digits 十
'十' => 10,
'十一' => 11,
'二十' => 20,
'二十一' => 21,
#3 digits 百
'一百' => 100,
'一百零一' => 101,
'一百一十' => 110,
'一百二十三' => 123,
#4 digits 千
'一千' => 1000,
'一千零一' => 1001,
'一千零一十' => 1010,
'一千一百' => 1100,
'一千零二十三' => 1023,
'一千二百零三' => 1203,
'一千二百三十' => 1230,
#5 digits 万
#@@@@
'一万' => 10000,
'一万零一' => 10001,
'一万零一十' => 10010,
'一万零一百' => 10100,
'一万一千' => 11000,
'一万零一十一' => 10011,
'一万零一百零一' => 10101,
'一万一千零一' => 11001,
'一万零一百一十' => 10110,
'一万一千零一十' => 11010,
'一万一千一百' => 11100,
'一万一千一百一十' => 11110,
'一万一千一百零一' => 11101,
'一万一千零一十一' => 11011,
'一万零一百一十一' => 10111,
'一万一千一百一十一' => 11111,
#6 digits 十万
'十万零二千三百四十五' => 102345,
'十二万三千四百五十六' => 123456,
'十万零三百五十六' => 100356,
'十万零三千六百零九' => 103609,
#7 digits 百万
'一百二十三万四千五百六十七' => 1234567,
'一百零一万零一百零一' => 1010101,
'一百万零一' => 1000001,
#8 digits 千万
'一千一百二十三万四千五百六十七' => 11234567,
'一千零一十一万零一百零一' => 10110101,
'一千万零一' => 10000001,
#9 digits 亿
'一亿一千一百二十三万四千五百六十七' => 111234567,
'一亿零一百零一万零一百零一' => 101010101,
'一亿零一' => 100000001,
#10 digits 十亿
'十一亿一千一百二十三万四千五百六十七' => 1111234567,
#11 digits 百亿
'一百一十一亿一千一百二十三万四千五百六十七' => 11111234567,
#12 digits 千亿
'一千一百一十一亿一千一百二十三万四千五百六十七' => 111111234567,
#13 digits 万亿
'一万一千一百一十一亿一千一百二十三万四千五百六十七' => 1111111234567,
#14 digits 十万亿
'十一万一千一百一十一亿一千一百二十三万四千五百六十七' => 11111111234567,
#17 digits 亿亿
'一亿一千一百一十一万一千一百一十一亿一千一百二十三万四千五百六十七' => 11111111111234567,
}
class Num2CnTest < Test::Unit::TestCase
def test_n2c
conv = NumCnConv.new
$td_map.each do |key, val|
uputs val.to_s + " => " + key
assert_equal key, conv.num2cn(val)
end
end
def test_c2n
conv = NumCnConv.new
$td_map.each do |key, val|
uputs key + " => " + val.to_s
assert_equal val, conv.cn2num(key)
end
end
end