大家好,欢迎来到IT知识分享网。
来源是看到知乎上一个奇葩问题:
任意大小的数字字符串转中文
其实10万以内的整数转换大写也太简单,今天我们要实现的是任意大小的数字字符串转大写。
首先我们要保证4位数以内的转换函数,能够处理各种含”0″的情况,代码:
import re ch_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 itertools num_t = "" 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个0 for 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 re ch_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 def 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("", 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_len num = "".join(nums) print(num, num2Chinese3(num))
33934 九千六百八十一万八千五百二十二亿 四千三百五十三万三千九百三十四 00004 八千五百二十二亿 四千三百五十三万三千九百三十四 33934 九千万零五百二十二亿 四千三百五十三万三千九百三十四 33934 九千六百万零二十二亿 四千三百五十三万三千九百三十四 33934 九千六百八十万零二亿 四千三百五十三万三千九百三十四 33934 九千六百八十一万亿 四千三百五十三万三千九百三十四 33934 九千六百八十一万八千亿 零三百五十三万三千九百三十四 33934 九千六百八十一万八千五百亿 零五十三万三千九百三十四 33934 九千六百八十一万八千五百二十亿 零三万三千九百三十四 03934 九千六百八十一万八千五百二十二亿 零三千九百三十四 00934 九千六百八十一万八千五百二十二亿 四千万零九百三十四 00034 九千六百八十一万八千五百二十二亿 四千三百万零三十四 00004 九千六百八十一万八千五百二十二亿 四千三百五十万零四 30000 九千六百八十一万八千五百二十二亿 四千三百五十三万 0000000 二亿 四千三百五十三万三千九百三十四 33934 九千万亿 四千三百五十三万三千九百三十四 33934 九千六百万亿 零三百五十三万三千九百三十四 33934 九千六百八十万亿 零五十三万三千九百三十四 33934 九千六百八十一万亿 零三万三千九百三十四 03934 九千六百八十一万八千亿 零三千九百三十四 00934 九千六百八十一万八千五百亿 零九百三十四 00034 九千六百八十一万八千五百二十亿 零三十四 00004 九千六百八十一万八千五百二十二亿 零四 00000 九千六百八十一万八千五百二十二亿 四千万 0000000000 五十三万三千九百三十四 33934 九千万亿 零三万三千九百三十四 03934 九千六百万亿 零三千九百三十四 00934 九千六百八十万亿 零九百三十四 00034 九千六百八十一万亿 零三十四 00004 九千六百八十一万八千亿 零四 00000 九千六百八十一万八千五百亿 0000000000000934 九百三十四 00034 九千万亿 零三十四 00004 九千六百万亿 零四 00000 九千六百八十万亿 0000000000000000 零
目测已经覆盖所有基本情况,下面我们测试一个带小数的超大数字:
num2Chinese(" 00000000 00 00000000 00000000 00000000 00000000 .00")
'九百五十万六千三百三十五亿亿亿亿亿亿亿亿亿亿亿 二千五百五十六万六千三百二十一亿亿亿亿亿亿亿亿亿亿 零一千八百九十四万五千七百六十亿亿亿亿亿亿亿亿 零四十二万四千五百八十四亿亿亿亿亿亿亿 五千四百四十四万四千四百四十四亿亿亿亿亿亿 零四千四百四十八万七千八百七十八亿亿 零四千四百四十八万七千八百七十八 点 零零九八零二一三'
测试一个python所支持的最大整数:
num2Chinese("")
'九百二十二亿亿 三千三百七十二万零三百六十八亿 五千四百七十七万五千八百零七'
可以初步判断能够正确转换。
中文数字转数字
上面我们连如此复杂的数字转中文都实现了,中文转数字将会变得非常简单,完整代码如下:
import re num_ch = dict(zip('零一二三四五六七八九', map(str, range(10)))) num_units = dict(zip('十百千', range(1, 4))) num_units[""] = 0 def Chinese2Num1(ch_num_str): if not re.search("[十百千]", ch_num_str): return "".join(num_ch[num] for num in ch_num_str) result = ["0"]*4 for 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_str2 return 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.search("[十百千万]", ch_num_str): return "".join(num_ch[num] for num in ch_num_str) 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('九百五十万六千三百三十五亿亿亿亿亿亿亿亿亿亿亿 二千五百五十六万六千三百二十一亿亿亿亿亿亿亿亿亿亿 零一千八百九十四万五千七百六十亿亿亿亿亿亿亿亿 零四十二万四千五百八十四亿亿亿亿亿亿亿 五千四百四十四万四千四百四十四亿亿亿亿亿亿 零四千四百四十八万七千八百七十八亿亿 零二百六十五万三千零二十一 点 零零九八零二一三')
'0000000000000000000000.00'
测试
接下面我们可以让两个转换函数互相转换,互相验证:
for i in range(0, 8, ): 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("未发现转换错误!")
经过半分钟的时间,已经初步互相验证完成,未发现转换失败的数据。
彩蛋:windows文件名排序
如何快速实现windows文件名的排序效果呢?示例代码:
files = os.listdir() files.sort(key=lambda s: [(s, int(n)) for s, n in re.findall('(\D+)(\d+)', f'a{
s}0')])
要支持能够根据中文大写数字排序,也只需要先将大写数字都转换为普通数字再用上述方法排序即可。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/151486.html