用Ruby做中文数字和阿拉伯数字之间的互相转换

 

#比如: 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

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值