字符串专题之中文大写金额数字转换工具

Python算法之旅

共 5335字,需浏览 11分钟

 ·

2021-06-11 11:13

说在前面

《数据与数据结构》是高中信息技术新教材选择性必修的一个重要组成部分,最近笔者在研究其中的一些内容,并尝试编写了一些题目与大家分享。

由于新教材是块新大陆,我们都是在摸索前行,加之本人水平有限,在描述题目用语和控制题目难度方面都存在不足,敬请大家批评指正。



12.(开放题)中文大写金额数字转换工具,可将输入的阿拉伯数字转换为中文大写金额数字。中文大写金额数字包括壹、贰、叁、肆、伍、陆、柒、捌、玖、拾、佰、仟、万、亿、元、角、分、零、整等字样。如下图所示:

人民币大写的正确写法:

一、中文大写金额数字前应标明“人民币”字样;

二、中文大写金额数字到“元”为止的,在“元”之后应写“整”;在“角”和“分”后面不写“整”字;

三、阿拉伯数字小写金额数字中有“0”时,中文大写应按照汉语语言规律、金额数字构成和防止涂改的要求进行书写。举例如下:

1、阿拉伯数字中间有“0”时,中文大写要写“零”字,如¥1409.50应写成人民币壹仟肆佰零玖元伍角;

2、阿拉伯数字中间连续有几个“0”时、中文大写金额中间可以只写一个“零”字,如¥6007.14应写成人民币陆仟零柒元壹角肆分。

3、阿拉伯金额数字万位和元位是“0”,或者数字中间连续有几个“0”,万位、元位也是“0”,但千位、角位不是“0”时,中文大写金额中可以只写一个零字,也可以不写“零”字,如¥1680.32应写成人民币壹仟陆佰捌拾元零叁角贰分,或者写成人民币壹仟陆佰捌拾元叁角贰分;又如¥107000.53应写成人民币壹拾万柒仟元伍角叁分,或者写成人民币壹拾万零柒仟元伍角叁分。

4、阿拉伯金额数字角位是“0”而分位不是“0”时,中文大写金额“元”后面应写“零”字,如¥16409.02应写成人民币壹万陆仟肆佰零玖元零贰分。

我们定义了一个自定义函数change (),它的功能是将输入的金额小写数字转换成人民币中文大写金额数字,其函数头说明如下:

函数功能:将小写数字转换成人民币中文大写金额数字。

函数名:change(num)

参数表:num – 输入的金额小写数字(整数或小数均可)。

返回值:人民币中文大写金额数字。

示例1:num=2305时,返回'人民币贰仟叁佰零伍元整';

示例2:num=108000.03时,返回'人民币壹拾万捌仟元零叁分'或'人民币壹拾万零捌仟元零叁分'。

请补充缺失的代码,并思考是否有其他实现方法:

def change(num):    max_num = 1000000000000  #最大转换金额数    if num >= max_num:        return "数额太大,数字需低于一万亿!"    units = "元拾佰仟万拾佰仟亿拾佰仟万拾佰仟"    digits = "零壹贰叁肆伍陆柒捌玖"    num = f'{num:0.2f}'    integral, decimal =num.split(".")  #分成整数和小数两个部分    ans = ""    flag =   ①              for i, d in enumerate(integral):   #处理整数部分        n = len(integral) - 1 - i #数字下标从高位开始数,单位下标从低位开始数        if d == "0":  #出现多个0时,并非输出所有的"零",需特殊处理"亿"和"万"位            if ((units[n]=="亿" or units[n]=="万") and ((i>=1 and integral[i-1]!='0') or (i>=2 andintegral[i-2]!='0') or (i>=3 and integral[i-3]!='0'))):                ans += units[n]            flag = True        else:            if flag:                ans += "零"            ans +=   ②                   flag = False    if ans != "" and integral[-1] =="0":#个位为0的特殊情况        ans += "元"    if decimal == "00":               ans += "整"    elif decimal[1] == "0":        ans += digits[int(decimal[0])] + "角"    elif decimal[0] == "0":        ans += "零" + digits[int(decimal[1])] + "分"    else:        ans +=   ③      return "人民币" + ans


答案:

① False或其他等效答案;
② digits[int(d)] + units[n]或其他等效答案 ;③digits[int(decimal[0])]+ "角" +digits[int(decimal[1])] + "分"或其他等效答案。


解析:

程序先对原始数据做保留2位小数处理,再把数据分成整数和小数两个部分。设置变量flag标记是否出现了数字0,初始值为False,表示还没有出现数字0,故第①空答案为False;接下来遍历整数部分,分别用变量i和n作为数字和单位的下标,数字下标从高位开始数,单位下标从低位开始数,二者恰好对称;若数字d为0时不急着输出(其中"亿"和"万"位的零在有必要时直接输出"亿"和"万"),只需标记flag = True即可;当数字d不为0时,看看前一个数字是否为0(即判断flag的值是否为True),若是则输出"零",然后输出当前的中文数字和对应单位,即第②空答案为digits[int(d)] + units[n]。
    接下来处理小数部分,按照规则分别处理各种特殊情况即可,第③空所在语句是不含0的情形,答案为digits[int(decimal[0])] + "角" +digits[int(decimal[1])] + "分"。


其他解法(一):

算法思想与题目算法相似,程序显示结果也一样,区别在于存储单位的数据结构不一样,本算法将倍率分成万以下单位和万以上单位,其中低倍率可以加在高倍率之前,例如拾万佰亿题目程序是直接使用下标定位"亿"和"万"位之前的低倍率单位,使用判断语句决定输出"亿"和"万";本程序是利用divmod函数求出万以下单位和万以上单位对应下标,再分别处理。

def change2(num):    max_num = 1000000000000  #最大转换金额数    if num >= max_num:        return "数额太大,数字需低于一万亿!"    digits = ["零","壹","贰","叁","肆","伍","陆","柒","捌","玖"]    low_radices = ["","拾","佰","仟"]    high_radices = ["","万","亿"]    num = f'{num:0.2f}'    integral, decimal = num.split(".")  #分成整数和小数两个部分    ans = ""    zero_count = 0    for i, d in enumerate(integral):   #处理整数部分         ph, pl = divmod(len(integral) - 1 - i, 4) #万以下单位和万以上单位对应下标        if d == "0":            zero_count += 1        else:            if zero_count > 0:                ans += "零"            zero_count = 0            ans += digits[int(d)] + low_radices[pl]        if pl == 0 and zero_count < 4:            ans += high_radices[ph]    if ans != "":        ans += "元"    if decimal == "00":                ans += "整"    elif decimal[1] == "0":        ans += digits[int(decimal[0])] + "角"    elif decimal[0] == "0":        ans += "零" + digits[int(decimal[1])] + "分"    else:        ans += digits[int(decimal[0])] + "角" + digits[int(decimal[1])] + "分"    return "人民币" + ans


其他解法(二):

算法思想较前面两种更巧妙,但程序显示结果略有不同(少了一些不必要的零)。程序的巧妙之处在于把零的读法存储在数组zero中,与单位数组units一一对应,这样无需另外再做判断,直接把单位或零拼接到结果字符串即可;除此以外,程序无需将整数和小数分开处理,只需去掉小数点,依次处理各个数字即可。由此付出的代价是需要在拼接结束后,专门处理多余的零或单位,较难理解,也容易出错。

def change3(num):    max_num = 1000000000000  #最大转换金额数    if num >= max_num:        return "数额太大,数字需低于一万亿!"    units = "分角元拾佰仟万拾佰仟亿拾佰仟"    digit = "零壹贰叁肆伍陆柒捌玖"    zero = "整零元零零零万零零零亿零零零" #零的读法    num = f'{num:0.2f}'.replace('.', '') #去掉小数点    ans = ""    for i, c in enumerate(num[::-1]):        if c == '0':   #按照零的读法拼接零            ans = zero[i] + ans        else:            ans = digit[int(c)] + units[i] + ans    #print(ans)    i = 1    while i < len(ans): #消除多余的零        if ans[i-1]=="零" and ans[i] in "亿万零元整":            ans = ans[:i-1] + ans[i:]        else:            i += 1    ans = ans.replace('亿万', '亿') #消除'亿万'的'万'    ans = ans.replace('角整', '角') #消除'角整'的'整'    if ans[0] == "元": ans = ans[1:]#消除多余的'元'    return "人民币" + ans


拓展思考:

上述3个程序能够处理的最大转换金额数均为一万亿(不含),现在要求增大最大转换金额到一万万亿(不含),又该如何编写代码呢?
提示:表示单位的数组units = "元拾佰仟万拾佰仟亿拾佰仟兆拾佰仟"。
写在后面

本公众号的原创文章都是本人平时工作和学习的一些心得体会文章,虽然经过长期认真地思考方才下笔,但由于笔者水平有限,难免出现一些错漏,敬请批评指正。

无论是赞同还是反对我的看法,都请你给我留言。如果你有新的想法,千万不要憋在心里,请发出来大家一起讨论。让我们相互学习,共同进步!


需要本文word版和拓展思考答案的,可以加入“Python算法之旅”知识星球参与讨论和下载文件,Python算法之旅”知识星球汇集了数量众多的同好,更多有趣的话题在这里讨论,更多有用的资料在这里分享。

我们专注Python算法,感兴趣就一起来!

相关优秀文章:

阅读代码和写更好的代码

最有效的学习方式

函数与模块典型例题

浏览 74
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报