Nav apraksta

an2cn.py 8.1KB

    # -*- coding: utf-8 -*- # from typing import Union from warnings import warn from .conf import NUMBER_LOW_AN2CN, NUMBER_UP_AN2CN, UNIT_LOW_ORDER_AN2CN, UNIT_UP_ORDER_AN2CN # from proces import preprocess class An2Cn(object): def __init__(self): self.all_num = "0123456789" self.number_low = NUMBER_LOW_AN2CN self.number_up = NUMBER_UP_AN2CN self.mode_list = ["low", "up", "rmb", "direct"] def an2cn(self, inputs=None, mode="low"): """阿拉伯数字转中文数字 :param inputs: 阿拉伯数字 :param mode: low 小写数字,up 大写数字,rmb 人民币大写,direct 直接转化 :return: 中文数字 """ if inputs is not None and inputs != "": if mode not in self.mode_list: raise ValueError(u"mode 仅支持 {} !".format(str(self.mode_list))) # 将数字转化为字符串,这里会有Python会自动做转化 # 1. -> 1.0 1.00 -> 1.0 -0 -> 0 if not isinstance(inputs, str): inputs = self.__number_to_string(inputs) # 数据预处理: # 1. 繁体转简体 # 2. 全角转半角 # inputs = preprocess(inputs, pipelines=[ # "traditional_to_simplified", # "full_angle_to_half_angle" # ]) # 检查数据是否有效 self.__check_inputs_is_valid(inputs) # 判断正负 if inputs[0] == "-": sign = u"负" inputs = inputs[1:] else: sign = "" if mode == "direct": output = self.__direct_convert(inputs) else: # 切割整数部分和小数部分 split_result = inputs.split(".") len_split_result = len(split_result) if len_split_result == 1: # 不包含小数的输入 integer_data = split_result[0] if mode == "rmb": output = self.__integer_convert(integer_data, "up") + u"元整" else: output = self.__integer_convert(integer_data, mode) elif len_split_result == 2: # 包含小数的输入 integer_data, decimal_data = split_result if mode == "rmb": int_data = self.__integer_convert(integer_data, "up") dec_data = self.__decimal_convert(decimal_data, "up") len_dec_data = len(dec_data) if len_dec_data == 0: output = int_data + u"元整" elif len_dec_data == 1: raise ValueError(u"异常输出:{}".format(dec_data)) elif len_dec_data == 2: if dec_data[1] != u"零": if int_data == u"零": output = dec_data[1] + u"角" else: output = int_data + u"元" + dec_data[1] + u"角" else: output = int_data + u"元整" else: if dec_data[1] != u"零": if dec_data[2] != u"零": if int_data == u"零": output = dec_data[1] + u"角" + dec_data[2] + u"分" else: output = int_data + u"元" + dec_data[1] + u"角" + dec_data[2] + u"分" else: if int_data == u"零": output = dec_data[1] + u"角" else: output = int_data + u"元" + dec_data[1] + u"角" else: if dec_data[2] != u"零": if int_data == u"零": output = dec_data[2] + u"分" else: output = int_data + u"元" + u"零" + dec_data[2] + u"分" else: output = int_data + u"元整" else: output = self.__integer_convert(integer_data, mode) + self.__decimal_convert(decimal_data, mode) else: raise ValueError(u"输入格式错误:{}!".format(inputs)) else: raise ValueError(u"输入数据为空!") return sign + output def __direct_convert(self, inputs): _output = "" for d in inputs: if d == ".": _output += u"点" else: _output += self.number_low[int(d)] return _output @staticmethod def __number_to_string(number_data): # 小数处理:python 会自动把 0.00005 转化成 5e-05,因此 str(0.00005) != "0.00005" string_data = str(number_data) if "e" in string_data: string_data_list = string_data.split("e") string_key = string_data_list[0] string_value = string_data_list[1] if string_value[0] == "-": string_data = "0." + "0" * (int(string_value[1:]) - 1) + string_key else: string_data = string_key + "0" * int(string_value) return string_data def __check_inputs_is_valid(self, check_data): # 检查输入数据是否在规定的字典中 all_check_keys = self.all_num + ".-" for data in check_data: if data not in all_check_keys: raise ValueError(u"输入的数据不在转化范围内:{}!".format(data)) def __integer_convert(self, integer_data, mode): if mode == "low": numeral_list = NUMBER_LOW_AN2CN unit_list = UNIT_LOW_ORDER_AN2CN elif mode == "up": numeral_list = NUMBER_UP_AN2CN unit_list = UNIT_UP_ORDER_AN2CN else: raise ValueError("error mode: {}".format(mode)) # 去除前面的 0,比如 007 => 7 integer_data = str(int(integer_data)) len_integer_data = len(integer_data) if len_integer_data > len(unit_list): raise ValueError(u"超出数据范围,最长支持 {} 位".format(len(unit_list))) output_an = "" for i, d in enumerate(integer_data): if int(d): output_an += numeral_list[int(d)] + unit_list[len_integer_data - i - 1] else: if not (len_integer_data - i - 1) % 4: output_an += numeral_list[int(d)] + unit_list[len_integer_data - i - 1] if i > 0 and not output_an[-1] == u"零": output_an += numeral_list[int(d)] output_an = output_an.replace(u"零零", u"零").replace(u"零万", u"万").replace(u"零亿", u"亿").replace(u"亿万", u"亿") \ .strip(u"零") # 解决「一十几」问题 if output_an[:2] in [u"一十"]: output_an = output_an[1:] # 0 - 1 之间的小数 if not output_an: output_an = u"零" return output_an def __decimal_convert(self, decimal_data, o_mode): len_decimal_data = len(decimal_data) if len_decimal_data > 16: warn(u"注意:小数部分长度为 {} ,将自动截取前 16 位有效精度!".format(len_decimal_data)) decimal_data = decimal_data[:16] if len_decimal_data: output_an = u"点" else: output_an = "" if o_mode == "low": numeral_list = NUMBER_LOW_AN2CN elif o_mode == "up": numeral_list = NUMBER_UP_AN2CN else: raise ValueError("error mode: {}".format(o_mode)) for data in decimal_data: output_an += numeral_list[int(data)] return output_an