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

2023-05-09,,

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

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

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

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

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

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

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

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

unitDic=dict(zip(range(8),u'拾佰仟万拾佰仟亿'))
numDic=dict(zip('',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]!='':
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]!='':
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=''+''*(i+1)
v2=''+''*i+''
v3=''*(i+2)
print ('%s->%s\n%s->%s\n%s->%s'% (v1,ChnNumber(v1),v2,ChnNumber(v2),v3,ChnNumber(v3)))
print ('%s->%s\n%s->%s\n%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]!='':
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))

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

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

下载本文的Word格式文档,以方便收藏与打印。