Python阿拉伯数字与中文互转
一、目标
(1)实现小数转换为中文的惯用读法。如:123.222读一百二十三点二二二。
(2)整十数和整百数等等,只读整的数位。如2000读两千,10读十。
(3)中间多个0只读一个零。如10086读一万零八十六。
(4)小于二十大于十的数习惯上不读前面的一。如12读十二。
二、源代码
对于代码的解析已写入代码的注释中,具体请参考注释。
# 数字转中文
class NTC:
def __init__(self):
self.dict = {'0': '零', '1': '一', '2': '二', '3': '三', '4': '四', '5': '五', '6': '六', '7': '七',
'8': '八', '9': '九', '.': '点'}
self.price = ['元', '角', '分']
self.base_unit = ['千', '百', '十']
self.level_unit = ['兆', '亿', '万']
# 输出['千兆', '百兆', '十兆', '兆', '千亿', '百亿', '十亿', '亿', '千万', '百万', '十万', '万', '千', '百', '十']
self.chapter_unit = [i + j for j in self.level_unit for i in self.base_unit + ['']] + self.base_unit
self.unit_values = [10 ** (len(self.chapter_unit) - i) for i in range(len(self.chapter_unit))]
# 大于0,以十进制形式输出。
def Num_to_Chi(self, num, mode):
change_list = []
# 整数部分的列表
chapter_list = []
# 小数部分的列表
decimal_list = []
last_zeros = 0
chapter = str(num)
# ------ 分离先处理小数点后面。 ------#
if '.' in chapter:
# 小数部分的字符串。
decimal = chapter[chapter.index('.') + 1:]
# 整数部分的字符串
integer = chapter[:chapter.index('.')]
# 删除小数部分后的整数字符串。
chapter = chapter[:chapter.index('.')]
decimal_list.append(self.dict['.'])
for d in decimal:
decimal_list.append(self.dict[d])
else:
# 没有小数部分,那就只有整数部分。
integer = num
# ------ 将数字全部变为中文,后面再插入。 ------#
# 这步可以不用,因为外接的函数支持整句话分离数字,已经有分离数字的设置。所以可以不用这步。
for i in chapter:
if i.isdigit():
change_list.append(self.dict[i])
else:
pass
# 如果是0的模式,是直接输出中文数字。
if mode == 0:
return ''.join(change_list)
else:
# ------ 得到最大位数的索引位置,该位数索引位置等于 位数的量 - (数字长度-1)。 ------#
d = len(self.chapter_unit) - (len(change_list) - 1)
# ------ 去除末尾多余的零。以实现100为一,110为,一一。 ------#
if float(integer) % 10 == 0:
for zero in change_list[::-1]:
if zero == '零':
last_zeros += 1
else:
break
change_list = change_list[:-last_zeros]
# ------ 筛选掉末尾的零的位数,即100为百,1000为千,1100为千百。而110为百十 ------#
if last_zeros - 1 > 0:
cu = self.chapter_unit[d:-(last_zeros - 1)]
else:
cu = self.chapter_unit[d:]
# ------ 依次交叉录入,先录入数字再接位数。 ------#
# 按照习惯,中间为零的时候是不读的。如10010,读成一万零一十。n作为录入过零后面还有零的提示参数,是过度变量。
n = 0
for i in range(len(cu)):
if change_list[i] == '零':
if n == 0:
n += 1
chapter_list.append('零')
else:
pass
else:
# 遇到数字后中间量归零。
n = 0
chapter_list.append(change_list[i])
chapter_list.append((cu[i]))
# 如果最后一个是零则不需要把个位数录入,不是要录入个位。
if last_zeros > 0:
pass
else:
chapter_list.append(change_list[-1])
# 按照习惯,像12,13,10这种读十二、十三、十,不读1。设置了model为2时关闭。
if float(num) > 20 or mode == 2:
pass
elif float(num) > 10:
chapter_list = chapter_list[1:]
return ''.join(chapter_list + decimal_list)
def Chi_to_Num(self, Chi):
values = self.dict.values()
cha_val_list = list(values)
Chi_num_list = []
for i in cha_val_list:
if i in Chi:
# 将所有中文数字和小数点替换成数字类。
Chi = Chi.replace(i, [k for k, v in self.dict.items() if v == i][0])
# 标记数字段的中间量
start = 0
end = 0
sign = 0
for i in range(len(Chi)):
# 获取数字段的开始位置,如果是数位开始,一定是十位数为1的两位数。
if Chi[i] in self.dict and sign == 0:
start = i
sign += 1
# 当匹配到的数既不是数字也不是数位,且标志不为0,则是数字段的结束。
elif Chi[i] not in self.dict and Chi[i] not in self.chapter_unit and sign != 0:
sign = 0
end = i
Chi_num_list.append((Chi[start:end],(start,end)))
# 匹配到数位开始的情况,即十位数为1的两位数。
elif Chi[i] in self.chapter_unit and sign == 0:
start = i
end = i+2
Chi_num_list.append((Chi[start:end],(start,end)))
# 整个字符串都是数字段的情况。
elif i == len(Chi) - 1:
end = i + 1
Chi_num_list.append((Chi[start:end], (start, end)))
for c in Chi_num_list:
# 分离小数部分。没有小数部分则为0。
if '.' in c[0]:
# 因为从这里分离了小数点,后面如果粘连了其他非数字,就得遍历判别,然后分离。
decimal_list = c[0][c[0].index('.'):]
for d in range( len(decimal_list) ): # 小数点的位置开始。
if decimal_list[d].isdigit():f = d + 1 # 索引获取最后一个要加1。
decimal = float(decimal_list[decimal_list.index('.'):f])
# 个位数,针对整百等情况。
if c[0][c[0].index('.') - 1].isdigit():bit = int(c[0][c[0].index('.') - 1])
else:bit = 0
else:
decimal = 0
# 个位数。
if c[0][-1].isdigit():bit = int(c[0][-1])
else:bit=0
# 遍历位数,匹配到就直接开始运算和循环相加。
result = 0 # 初始化最初结果。
for i in range(len(self.chapter_unit)):
if self.chapter_unit[i] in c[0]:
# 检索位数的位置
Chi_index = c[0].index(self.chapter_unit[i])
# 位数前一定是个数字,所以位数对应的值乘以这个数字。除了十,前面可能还要补一。
if Chi_index == 0:
result = self.unit_values[i]
else:
result = int(c[0][Chi_index - 1]) * self.unit_values[i] + result
# print('1',result)
result = result + bit + decimal
# print('2', result)
# print('3',Chi)
Chi = Chi.replace(Chi[c[1][0]:c[1][1]],str(result))
# print('4',Chi)
return Chi
'''
mode = 0或n n指其他数字,为只将数字硬转成中文。
mode = 1 为日常的数字读法。
mode = 2 关闭十属数的习惯性纠正,11读为一十一。
'''
def Num_to_Chi(num, model=1):
ntc = NTC()
# 传入文段如果多个数字段。
nums_list = []
# 中间量
num_list = [] # 用于存储一个数字段。
no_num = 0 # 用于判断是否匹配了一个数字段。
num = str(num)
for i in num + 'e': # 加个e作为结束的符号,防止输入只有数字,else阶段直接跳过没输入到nums_list里。
# 将匹配到的数字放入列表中。
if i in ntc.dict.keys():
num_list.append(i)
no_num = 1
else:
# 如果有数字段,添加到列表内,待转换。
if no_num == 1:
nums_list.append((''.join(num_list)))
no_num = 0
num_list = []
else:
pass
if nums_list:
for l in nums_list:
chi_num = ntc.Num_to_Chi(l, model)
num = num.replace(l, chi_num)
return num
def Chi_to_Num(Chi):
ntc = NTC()
NChi = Chi
# ------ 筛选输入的字符串里的数字内容,排除数字干扰。 ------ #
for i in Chi:
if i.isdigit():
NChi = NChi.replace(i,"|")
if "|" in NChi:
Chi_list = NChi.split("|")
else:
Chi_list = [Chi]
for i in range(len(Chi_list)):
_l = ntc.Chi_to_Num(Chi_list[i])
if _l != '':
Chi = Chi.replace(Chi_list[i],_l)
return Chi
# 数字转中文测试
# print("********数字转中文测试********")
# # 日常模式。
# print("单个数字",Num_to_Chi(1)) # 单个数字
# print("单个字符数字",Num_to_Chi('1')) # 单个字符数字
# print("十位数为1的数字",Num_to_Chi(12))
# print("整百数",Num_to_Chi(400))
# print("整百数小数",Num_to_Chi(400.202))
# print("附带其他的字符串",Num_to_Chi('s12.225元244了'))
# # 硬转模式
# print("十位数为1的数字",Num_to_Chi(12,0))
'''
结果
单个数字 一
单个字符数字 一
十位数为1的数字 十二
整百数 四百
整百数小数 四百点二零二
附带其他的字符串 s十二点二二五元二百四十四了
十位数为1的数字 一二
'''
# 中间多个零也无所谓,两者输出一样 100000200.448
print("********中文转数字测试********")
print("无输入",Chi_to_Num(''))
print("单个数字",Chi_to_Num('一'))
print("携带阿拉伯数字的字符串",Chi_to_Num('12一'))
print("十位数为1的两位数",Chi_to_Num('十一'))
print("普通的两位数",Chi_to_Num('四十一'))
print("整百",Chi_to_Num('四百'))
print("整百小数",Chi_to_Num('四十点二二'))
print("中间有零和周围有其他字符",Chi_to_Num('你好,总共一亿零二百零三点四四八元'))
print("中间多个零也没关系",Chi_to_Num('一共一亿零零二百零三点四四八元'))
'''
结果
无输入
单个数字 1
携带阿拉伯数字的字符串 121
十位数为1的两位数 11
普通的两位数 41
整百 400
整百小数 40.22
中间有零和周围有其他字符 你好,总共100000203.448元
中间多个零也没关系 1共100000203.448元
'''
三、后续
对于想要实现中文大写与数字互转,请自行修改其中的中文对应的数。
而只是代码仍有一定的局限性,最好是打包成exe,更加方便于使用。后续笔者再进行打包。