• 用Python递归解决阿拉伯数字转为中文财务数字格式的问题(2)--打开思路的一种方法


    几天前自己写了个将阿拉伯数字转为中文财务数字的程序.用的递归,不幸的是它是树形递归.

    虽然实际过程中不太可能出现金额数字大到让Python递归栈溢出,但是始终是一块心病,这玩意终究在理论上是受限制的.

    我持续地零散地思考过这个问题,今天终于将其一举拿下,并且还是两个版本,一个是函数式(尾递归),一个是命令式.总算是解决一个心病了.

    关键在于哪?原来的思路是从左到右转换数字,这种思路用树形递归表示并不难,但是你尝试转化为尾递归时会让你欲仙欲死..反正我是没有弄出来,还浪费了很多时间.

    不知怎么的,我突然想到尝试从右到左转换,一下子就豁然开朗了.

    我首先写出了个命令式版本,随后轻松翻译为尾递归版本..

    这让我想起以前下象棋时,用车纵向将军后,突然发现,如果横向将军直接就赢了啊!这算是一种打开思路的方法了,即尝试从另外一个原始的位置或者方向思考如何解决问题...

    是这样吗?是的,字符串从左到右和从右到左够原始吧.

    unitDic=dict(zip(range(8),u'拾佰仟万拾佰仟亿'))
    numDic=dict(zip('0123456789',u'零壹贰叁肆伍陆柒捌玖'))
    wapDic=[(u'零拾',u''),(u'零佰',u''),(u'零仟',u''),
            (u'零万',u''),(u'零亿',u'亿'),(u'亿万',u'亿'),
            (u'零零',u''),]
    
    #函数式
    def ChnNumber(s):
        def wrapper(s,wd=wapDic):
            def rep(s,k,v):
                if k in s:
                    return rep(s.replace(k,v),k,v)
                return s    
            if not wd:
                return s
            return wrapper(rep(s,*wd[0]),wd[1:])
        def recur(s,acc='',ind=0):        
            if s=='':
                return acc
            return recur(s[:-1],numDic[s[-1]]+unitDic[ind%8]+acc,ind+1)
        def end(s):
            if s[-1]!='0':
                return numDic[s[-1]]
            return ''
        def result(start,end):
            if end=='' and start[-1]==u'':
                return start[:-1]
            return start+end
        return result(wrapper(recur(s[:-1])),end(s))
    
    #命令式
    def xChnNumber(s):
        def wrapper(s):
            for k,v in wapDic:
                while k in s:
                    s=s.replace(k,v)
            return s   
        def cmd(s):
            start=''
            for i,char in enumerate(s[::-1]):
                start=numDic[char]+unitDic[i%8]+start
            return start
        def end(s):
            if s[-1]!='0':
                return numDic[s[-1]]
            return ''
        def result(start,end):
            if end=='' and start[-1]==u'':
                return start[:-1]
            return start+end
        return result(wrapper(cmd(s[:-1])),end(s))

    测试代码:

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

    当然Python的尾递归需要特别手段才不会在超大数字的时候出错(比如10000位数字),针对函数版,有以下办法:

    class TailCaller(object) :
        def __init__(self, f) :
            self.f = f
        def __call__(self, *args, **kwargs) :
            ret = self.f(*args, **kwargs)
            while type(ret) is TailCall :
                ret = ret.handle()
            return ret
    
    class TailCall(object) :
        def __init__(self, call, *args, **kwargs) :
            self.call = call
            self.args = args
            self.kwargs = kwargs
        def handle(self) :
            if type(self.call) is TailCaller :
                return self.call.f(*self.args, **self.kwargs)
            else :
                return self.f(*self.args, **self.kwargs)
    
    def ChnNumber(s):
        def wrapper(s,wd=wapDic):
            @TailCaller
            def rep(s,k,v):
                if k in s:
                    return TailCall(rep,s.replace(k,v),k,v)
                return s    
            if not wd:
                return s
            return wrapper(rep(s,*wd[0]),wd[1:])
        @TailCaller
        def recur(s,acc='',ind=0):        
            if s=='':
                return acc
            return TailCall(recur,s[:-1],numDic[s[-1]]+unitDic[ind%8]+acc,ind+1)
        def end(s):
            if s[-1]!='0':
                return numDic[s[-1]]
            return ''
        def result(start,end):
            if end=='' and start[-1]==u'':
                return start[:-1]
            return start+end
        return result(wrapper(recur(s[:-1])),end(s))
  • 相关阅读:
    Linux 查看内存状态
    Linux sar工具安装使用
    DNS ARP地址解析原理
    TCP/UDP 端口
    TCP/IP 传输原理
    Window vagrant 安装部署【转】
    Window7下vagrant的部署
    Ubuntu下访问SSH
    使用 Vagrant 打造跨平台开发环境
    Vagrant入门[转]
  • 原文地址:https://www.cnblogs.com/xiangnan/p/3411100.html
Copyright © 2020-2023  润新知