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

虽然实际过程中不太可能出现金额数字大到让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)--打开思路的一种方法的更多相关文章

  1. .Net C# 阿拉伯数字转为中文金额数字

    一个练习,将阿拉伯数字转为中文金额数字,针对包含整数的金额有问题 代码: public string ReturnStr(string inputNum) { ", }; string[] ...

  2. Java 阿拉伯数字转换为中文大写数字

    Java 阿拉伯数字转换为中文大写数字 /** * <html> * <body> * <P> Copyright 1994 JsonInternational&l ...

  3. 解决vue项目eslint校验 Do not use &#39;new&#39; for side effects 的两种方法

    import Vue from 'vue' import App from './App.vue' import router from './router' new Vue({ el: '#app' ...

  4. PyQt(Python+Qt)学习随笔:QTableWidget中表格各列平均分配宽度的两种方法

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 在QTableWidget表格部件中,如果需要实现表格中各列要占满部件中的可用空间,同时实现各列平分 ...

  5. python将nan, inf转为特定的数字

    最近,处理两个矩阵的点除,得到结果后,再作其他的计算,发现有些内置的函数不work:查看得到的数据,发现有很多nan和inf,导致python的基本函数运行不了,这是因为在除的过程中分母出现0的缘故. ...

  6. 阿拉伯数字转中文大写数字的JS

    function intToChinese ( str ) { str = str+''; var len = str.length-1; var idxs = ['','十','百','千','万' ...

  7. python打开浏览器的三种方法

    1.startfile方法 import os os.startfile("C:\Program Files (x86)\Google\Chrome\Application\chrome.e ...

  8. html table表格导出excel的方法 html5 table导出Excel HTML用JS导出Excel的五种方法 html中table导出Excel 前端开发 将table内容导出到excel HTML table导出到Excel中的解决办法 js实现table导出Excel,保留table样式

    先上代码   <script type="text/javascript" language="javascript">   var idTmr; ...

  9. Oracle中中文、数字,英文混杂形式的字段进行排序的方法

    http://blog.csdn.net/p451933505/article/details/9272257 对Oracle中中文.数字.英文混杂形式的字段进行排序的方法: 例如: order by ...

随机推荐

  1. 使用FileSystemWatcher监视文件变化

    本文转载:http://www.cnblogs.com/zanxiaofeng/archive/2011/01/08/1930583.html FileSystemWatcher基础 属性: Path ...

  2. 多重和嵌套if

    多重if实例: 看例子,内容不解释了! 隐藏行号 复制代码 ? 多重if import java.util.Scanner; public class 多重if{ public static void ...

  3. C#钩子应用实例

    C#钩子应用实例一.写在最前 本文的内容只想以最通俗的语言说明钩子的使用方法,具体到钩子的详细介绍可以参照下面的网址: http://www.microsoft.com/china/community ...

  4. android视频播放器系列(一)——系统播放器

    使用系统播放器(intent隐士调用)可以播放本地视频和网络视频,但是使用方式上稍微有点差别: 一.播放本地视频 Uri uri = Uri.parse("本地视频地址");Int ...

  5. 【JAVA】文件各行打乱

    给定一个文件,把文件 里的各行打乱,并验证其正确性,时间紧迫,随手写写 String path = "/Users/guangyi.zgy/Desktop/scene_2khas_8kno_ ...

  6. textarea如何实现高度自适应?

    今天需要些一个回复评论的页面,设计师给的初始界面就是一个只有一行的框.然后当时就想这个交互该怎么实现比较好,然后想起了新浪微博的做法:点击评论,默认显示一行,当输入的文字超过一行或者输入Enter时, ...

  7. 將UNITY作品上傳到Facebook App!

    前言 大家好,今天要來介紹如何用UNITY 將製作好的遊戲上傳到Facebook,也就是Facebook App.近期Facebook與Unity合作而推出了新的插件,利用插件可上傳分數.邀請好友.P ...

  8. codeforces 980E The Number Games

    题意: 给出一棵树,要求去掉k个点,使得剩下的还是一棵树,并且要求Σ(2^i)最大,i是剩下的节点的编号. 思路: 要使得剩下的点的2的幂的和最大,那么肯定要保住大的点,这是贪心. 考虑去掉哪些点的话 ...

  9. day 09 初识函数

    今日主要学习了 一. 什么是函数二. 函数定义, 函数名, 函数体以及函数的调?三. 函数的返回值四. 函数的参数 一, 什么是函数               如果找不到合适的函数名称 ,用 fu ...

  10. cpu高占用,线程堆栈,jstack,pstack,jmap, kill -3 pid,java(weblogic,tomcat)

    1 ps -mp pid -o THREAD,tid,time 2 printf "%x\n" tid 3 jstack pid |grep tid -A 30