用Python递归解决阿拉伯数字转为中文财务数字格式的问题

 

现在心情还是有点小小激动的.因为我发现递归开始渗透到有实际意义的问题的求解中了.把数字1111转换为"壹仟壹佰壹拾壹",这应该是银行记录和打印数字的基础环节了.

 

我以前看有人说,递归不是人类自然的思考方式。现在我感到非常不可理解,因为我感觉完全相反.

在今天这个程序的实现上,我是自然而然地想到用递归来求解这个复杂的问题.

因为我一开始只知道一些简单的情况该怎么做,例如:

如果给的是1位数,显然非常简单,按照numDic字典直接给结果就行.

如果给的是2位数,也不难.取十位数,按照numDic字典返回字符,然后和单位"十"连接,最后再和个位数字符连接.

如果给的是3位数,也不难.取百位数,按照numDic字典返回字符,然后和单位"百"连接,剩余的十位数和个位数按照之前的规则进行处理.

...

这样思考,我发现原来最基本的单位是9亿9千9百9十9万9千9百9十9.

因为比这个数字大的数,都可以转换为2个更小的部分,比如10亿,其实等于从亿位数划分的两部分字符,左边是"10",中间是单位"亿",后面是8个"0".

而"10"不正是2位数的情况,8个"0"不正是8位数的情况吗?而这2种情况不就是刚好属于已知的简单的基本情形吗?

 

至此,就算你给我1000位数,我也能给你分析出来了.你要叫我用其他方法来解,我无法找到思考的入口.

 

直接上源码:

 

# -*- coding:utf-8 -*-
'''中文财务数字转换程序.
例如11111,可转换为:壹万壹仟壹佰壹拾壹
"万仟佰拾"就是"单位","壹"就是"数值"
'''

unitArab=(2,3,4,5,9)
unitStr=u'十百千万亿'
unitStr=u'拾佰仟万亿'
#单位字典unitDic,例如(2,'十')表示给定的字符是两位数,那么返回的结果里面定会包含'十'.3,4,5,9以此类推.
unitDic=dict(zip(unitArab,unitStr))

numArab=u'0123456789'
numStr=u'零一二三四五六七八九'
numStr=u'零壹贰叁肆伍陆柒捌玖'
#数值字典numDic,和阿拉伯数字是简单的一一对应关系
numDic=dict(zip(numArab,numStr))


def ChnNumber(s):
    def wrapper(v):
        '''针对多位连续0的简写规则设计的函数
        例如"壹佰零零"会变为"壹佰","壹仟零零壹"会变为"壹仟零壹"
        '''
        if u'零零' in v:
            return wrapper(v.replace(u'零零',u''))
        return v[:-1] if v[-1]==u'' else v
    def recur(s,bit):
        '''此函数接收2个参数:
        1.纯数字字符串
        2.此字符串的长度,相当于位数'''
        #如果是一位数,则直接按numDic返回对应汉字
        if bit==1:
            return numDic[s]
        #否则,且第一个字符是0,那么省略"单位"字符,返回"零"和剩余字符的递归字符串
        if s[0]==u'0':
            return wrapper(u'%s%s' % (u'',recur(s[1:],bit-1)))
        #否则,如果是2,3,4,5,9位数,那么返回最高位数的字符串"数值"+"单位"+"剩余字符的递归字符串"
        if bit<6 or bit==9:
            return wrapper(u'%s%s%s' % (numDic[s[0]],unitDic[bit],recur(s[1:],bit-1)))
        #否则,如果是6,7,8位数,那么用"万"将字符串从万位数划分为2个部分.
        #例如123456就变成:12+"万"+3456,再对两个部分进行递归.
        if bit<9:
            return u'%s%s%s' % (recur(s[:-4],bit-4),u"",recur(s[-4:],4))
        #否则(即10位数及以上),用"亿"仿照上面的做法进行划分.
        if bit>9:
            return u'%s%s%s' % (recur(s[:-8],bit-8),u"亿",recur(s[-8:],8))
    return recur(s,len(s))

for i in range(18):    
    v1='9'+'0'*(i+1)
    v2='9'+'0'*i+'9'
    v3='1'*(i+2)
    print ('%s->%s\n%s->%s\n%s->%s'% (v1,ChnNumber(v1),v2,ChnNumber(v2),v3,ChnNumber(v3)))

 

 

 

结果:

>>> 
90->玖拾
99->玖拾玖
11->壹拾壹
900->玖佰
909->玖佰零玖
111->壹佰壹拾壹
9000->玖仟
9009->玖仟零玖
1111->壹仟壹佰壹拾壹
90000->玖万
90009->玖万零玖
11111->壹万壹仟壹佰壹拾壹
900000->玖拾万
900009->玖拾万零玖
111111->壹拾壹万壹仟壹佰壹拾壹
9000000->玖佰万
9000009->玖佰万零玖
1111111->壹佰壹拾壹万壹仟壹佰壹拾壹
90000000->玖仟万
90000009->玖仟万零玖
11111111->壹仟壹佰壹拾壹万壹仟壹佰壹拾壹
900000000->玖亿
900000009->玖亿零玖
111111111->壹亿壹仟壹佰壹拾壹万壹仟壹佰壹拾壹
9000000000->玖拾亿
9000000009->玖拾亿零玖
1111111111->壹拾壹亿壹仟壹佰壹拾壹万壹仟壹佰壹拾壹
90000000000->玖佰亿
90000000009->玖佰亿零玖
11111111111->壹佰壹拾壹亿壹仟壹佰壹拾壹万壹仟壹佰壹拾壹
900000000000->玖仟亿
900000000009->玖仟亿零玖
111111111111->壹仟壹佰壹拾壹亿壹仟壹佰壹拾壹万壹仟壹佰壹拾壹
9000000000000->玖万亿
9000000000009->玖万亿零玖
1111111111111->壹万壹仟壹佰壹拾壹亿壹仟壹佰壹拾壹万壹仟壹佰壹拾壹
90000000000000->玖拾万亿
90000000000009->玖拾万亿零玖
11111111111111->壹拾壹万壹仟壹佰壹拾壹亿壹仟壹佰壹拾壹万壹仟壹佰壹拾壹
900000000000000->玖佰万亿
900000000000009->玖佰万亿零玖
111111111111111->壹佰壹拾壹万壹仟壹佰壹拾壹亿壹仟壹佰壹拾壹万壹仟壹佰壹拾壹
9000000000000000->玖仟万亿
9000000000000009->玖仟万亿零玖
1111111111111111->壹仟壹佰壹拾壹万壹仟壹佰壹拾壹亿壹仟壹佰壹拾壹万壹仟壹佰壹拾壹
90000000000000000->玖亿亿
90000000000000009->玖亿亿零玖
11111111111111111->壹亿壹仟壹佰壹拾壹万壹仟壹佰壹拾壹亿壹仟壹佰壹拾壹万壹仟壹佰壹拾壹
900000000000000000->玖拾亿亿
900000000000000009->玖拾亿亿零玖
111111111111111111->壹拾壹亿壹仟壹佰壹拾壹万壹仟壹佰壹拾壹亿壹仟壹佰壹拾壹万壹仟壹佰壹拾壹

 

posted @ 2013-10-31 21:45  LisPythoniC  阅读(2224)  评论(0编辑  收藏  举报