环球网校是美国纳斯达克上市企业欢聚时代(NASDAQ:YY)旗下品牌 | 住房和城乡建设部 建筑人才培训合作单位
您现在的位置在: > 外语考试 > 职称英语 > 考试动态 >

如何快速实现任意大小的数字字符串转大写的简单

2023-11-25 来源:网络 作者:佚名

来源是听到知乎上一个雷人问题:

任意大小的数字字符串转英文 #

虽然10万以内的整数转换小写也太简单,明天我们要实现的是任意大小的数字字符串转小写。

#

首先我们要保证4位数以内的转换函数大写数字转换,就能处理各类含"0"的情况,代码:

#

import rech_num = '零一二三四五六七八九'
units = ' 十百千'def num2Chinese1(num_str):"转换9999以内的数字到大写"result = [ch_num[int(i)]+unit for i,unit in zip(reversed(num_str), units)]result = "".join(reversed(result))result = re.sub("(?:零[十百千])+", "零", result)result = re.sub("零+", "零", result)result = result.rstrip()if result != "零":result = result.rstrip("零")return result
 # 
#

之后生成测试用例并测试: #

import random
import itertoolsnum_t = "123456789"
cases = []
for length in range(1, 5):nums = random.sample(num_t, length)cases.append("".join(nums))for n in range(1, length+1):# n个0for poss in itertools.combinations(range(length), n):num = nums.copy()for pos in poss:num[length-pos-1] = "0"num = "".join(num)cases.append(num)
for i in cases:print(i, num2Chinese1(str(i)))
 # 
#

6 六
0 零
54 五十四
50 五十
04 零四
00 零
831 八百三十一
830 八百三十
801 八百零一
031 零三十一
800 八百
030 零三十
001 零一
000 零
6895 六千八百九十五
6890 六千八百九十
6805 六千八百零五
6095 六千零九十五
0895 零八百九十五
6800 六千八百
6090 六千零九十
0890 零八百九十
6005 六千零五
0805 零八百零五
0095 零九十五
6000 六千
0800 零八百
0090 零九十
0005 零五
0000 零
 # 

#

保证了四位数的处理函数没有问题后,之后就可以开始编撰才能支持任意位数的处理函数,并将转换函数升级到支持小数。

#

import math
import rech_num = '零一二三四五六七八九'
units = ' 十百千'def num2Chinese1(num_str):"转换9999以内的数字到大写"result = [ch_num[int(i)]+unit for i,unit in zip(reversed(num_str), units)]result = "".join(reversed(result))result = re.sub("(?:零[十百千])+", "零", result)result = re.sub("零+", "零", result)result = result.rstrip()if result != "零":result = result.rstrip("零")return resultdef num2Chinese2(num_str):if len(num_str) <= 4:result = num2Chinese1(num_str[-4:])else:result = num2Chinese1(num_str[:-4]) + "万" + num2Chinese1(num_str[-4:])return result.replace("零万", "零")def num2Chinese3(num_str):num_str = num_str.lstrip("0")if not num_str:return "零"if len(num_str) <= 4:return num2Chinese1(num_str)e_num = math.ceil(len(num_str)/8)result = [num2Chinese2(num_str[-8:])]for e_i in range(1, e_num):result.append(num2Chinese2(num_str[-8-e_i*8:-e_i*8])+"亿"*e_i+" ")result = "".join(reversed(result))result = re.sub(" (?:零+亿+ )+", " 零", result)result = re.sub("零(亿+)", r"\1", result)result = re.sub("零+", "零", result)return result.strip("零")def num2Chinese(num_str):num_str = num_str.replace(" ", "").rstrip(".")if not re.fullmatch("\d+(?:\.\d+)?", num_str):raise Exception("不是一个数字字符串")if num_str.find(".") != -1:num_str1, num_str2 = num_str.split(".", 1)return num2Chinese3(num_str1)+" 点 "+"".join(ch_num[int(c)] for c in num_str2.rstrip("0"))return num2Chinese3(num_str)
 # 
#

下边我们生成千万亿级别的各类具备代表性的测试数据进行测试:

#

nums_t = random.choices("123456789", k=16)
num = "".join(nums_t)
print(num, num2Chinese(num))
for zero_len in range(4, 15, 3):for s_pos in range(17-zero_len):nums = nums_t.copy()nums[s_pos:s_pos+zero_len] = "0"*zero_lennum = "".join(nums)print(num, num2Chinese3(num))
 
#
#

9681852243533934 九千六百八十一万八千五百二十二亿 四千三百五十三万三千九百三十四
0000852243533934 八千五百二十二亿 四千三百五十三万三千九百三十四
9000052243533934 九千万零五百二十二亿 四千三百五十三万三千九百三十四
9600002243533934 九千六百万零二十二亿 四千三百五十三万三千九百三十四
9680000243533934 九千六百八十万零二亿 四千三百五十三万三千九百三十四
9681000043533934 九千六百八十一万亿 四千三百五十三万三千九百三十四
9681800003533934 九千六百八十一万八千亿 零三百五十三万三千九百三十四
9681850000533934 九千六百八十一万八千五百亿 零五十三万三千九百三十四
9681852000033934 九千六百八十一万八千五百二十亿 零三万三千九百三十四
9681852200003934 九千六百八十一万八千五百二十二亿 零三千九百三十四
9681852240000934 九千六百八十一万八千五百二十二亿 四千万零九百三十四
9681852243000034 九千六百八十一万八千五百二十二亿 四千三百万零三十四
9681852243500004 九千六百八十一万八千五百二十二亿 四千三百五十万零四
9681852243530000 九千六百八十一万八千五百二十二亿 四千三百五十三万
0000000243533934 二亿 四千三百五十三万三千九百三十四
9000000043533934 九千万亿 四千三百五十三万三千九百三十四
9600000003533934 九千六百万亿 零三百五十三万三千九百三十四
9680000000533934 九千六百八十万亿 零五十三万三千九百三十四
9681000000033934 九千六百八十一万亿 零三万三千九百三十四
9681800000003934 九千六百八十一万八千亿 零三千九百三十四
9681850000000934 九千六百八十一万八千五百亿 零九百三十四
9681852000000034 九千六百八十一万八千五百二十亿 零三十四
9681852200000004 九千六百八十一万八千五百二十二亿 零四
9681852240000000 九千六百八十一万八千五百二十二亿 四千万
0000000000533934 五十三万三千九百三十四
9000000000033934 九千万亿 零三万三千九百三十四
9600000000003934 九千六百万亿 零三千九百三十四
9680000000000934 九千六百八十万亿 零九百三十四
9681000000000034 九千六百八十一万亿 零三十四
9681800000000004 九千六百八十一万八千亿 零四
9681850000000000 九千六百八十一万八千五百亿 
0000000000000934 九百三十四
9000000000000034 九千万亿 零三十四
9600000000000004 九千六百万亿 零四
9680000000000000 九千六百八十万亿 
0000000000000000 零
 
#
#

目测早已覆盖所有基本情况,下边我们测试一个带小数的超大数字:

#

num2Chinese("9506335 25566321 00000000 18945760 00424584 54444444 00000000 00000000 00000000 44487878 00000000 44487878.00980213")
 

#

#

'九百五十万六千三百三十五亿亿亿亿亿亿亿亿亿亿亿 二千五百五十六万六千三百二十一亿亿亿亿亿亿亿亿亿亿 零一千八百九十四万五千七百六十亿亿亿亿亿亿亿亿 零四十二万四千五百八十四亿亿亿亿亿亿亿 五千四百四十四万四千四百四十四亿亿亿亿亿亿 零四千四百四十八万七千八百七十八亿亿 零四千四百四十八万七千八百七十八 点 零零九八零二一三'
 # 
#

测试一个所支持的最大整数:

#

num2Chinese("9223372036854775807")
 # 
#

'九百二十二亿亿 三千三百七十二万零三百六十八亿 五千四百七十七万五千八百零七'
 # 

#

可以初步判定才能正确转换。

#

英文数字转数字 #

前面我们连这么复杂的数字转英文都实现了,英文转数字将会显得十分简单,完整代码如下: #

import renum_ch = dict(zip('零一二三四五六七八九', map(str, range(10))))
num_units = dict(zip('十百千', range(1, 4)))
num_units[""] = 0def Chinese2Num1(ch_num_str):result = ["0"]*4for num, unit in re.findall("([^零十百千])([十百千]|$)", ch_num_str):result[num_units[unit]] = num_ch[num]result.reverse()return "".join(result)def Chinese2Num2(ch_num_str):if ch_num_str.find("万") != -1:ch_num_str1, ch_num_str2 = map(Chinese2Num1, ch_num_str.split("万", 1))return ch_num_str1 + ch_num_str2return Chinese2Num1(ch_num_str).zfill(8)def Chinese2Num3(ch_num_str):data = re.findall("[ 零]*([^亿]+)(亿+|$)", ch_num_str)result = ["0"*8]*(len(data[0][1])+1)for Chinese_str, e_str in data:result[len(e_str)] = Chinese2Num2(Chinese_str)result.reverse()return "".join(result).lstrip("0")def Chinese2Num(ch_num_str):ch_num_str = ch_num_str.replace(" ", "").rstrip("点零")if ch_num_str == "":return "0"if not re.fullmatch("[零一二三四五六七八九十百千万亿]+(?:点[零一二三四五六七八九十百千万亿]+)?", ch_num_str):raise Exception(f"{ch_num_str}存在非法字符,无法转换")if ch_num_str.find("点") != -1:ch_num_str1, ch_num_str2 = ch_num_str.split("点", 1)return Chinese2Num3(ch_num_str1)+"."+"".join(num_ch[c] for c in ch_num_str2).rstrip("0")return Chinese2Num3(ch_num_str)
 

#

#

测试一下: #

Chinese2Num('九百五十万六千三百三十五亿亿亿亿亿亿亿亿亿亿亿 二千五百五十六万六千三百二十一亿亿亿亿亿亿亿亿亿亿 零一千八百九十四万五千七百六十亿亿亿亿亿亿亿亿 零四十二万四千五百八十四亿亿亿亿亿亿亿 五千四百四十四万四千四百四十四亿亿亿亿亿亿 零四千四百四十八万七千八百七十八亿亿 零二百六十五万三千零二十一 点 零零九八零二一三')
 # 
#

'95063352556632100000000189457600042458454444444000000000000000000000000444878780000000002653021.00980213'
 
#
#

测试 #

接下边我们可以让两个转换函数相互转换,相互验证: #

for i in range(0, 720368547758, 900025):a = str(i)ch_num_str = num2Chinese(a)b = Chinese2Num(ch_num_str)if a != b:print(a, ch_num_str, b)break
else:print("未发现转换错误!")
 # 
#

经过半分钟的时间大写数字转换,早已初步相互验证完成,未发觉转换失败的数据。 #

彩蛋:文件名排序

#

怎样快速实现文件名的排序疗效呢?示例代码:

#

files = os.listdir()
files.sort(key=lambda s: [(s, int(n)) for s, n in re.findall('(\D+)(\d+)', f'a{s}0')])
 
#
#

要支持才能依据英文小写数字排序,也只须要先将小写数字都转换为普通数字再用上述方式排序即可。 #

责编:admin 返回顶部  打印

关于我们联系我们友情链接网站声明网站地图广告服务帮助中心