@@ -0,0 +1,16 @@  | 
            ||
| 1 | 
                +__version__ = "0.5.22"  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from .cn2an import Cn2An  | 
            |
| 4 | 
                +from .an2cn import An2Cn  | 
            |
| 5 | 
                +from .transform import Transform  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +cn2an = Cn2An().cn2an  | 
            |
| 8 | 
                +an2cn = An2Cn().an2cn  | 
            |
| 9 | 
                +transform = Transform().transform  | 
            |
| 10 | 
                +  | 
            |
| 11 | 
                +__all__ = [  | 
            |
| 12 | 
                + "__version__",  | 
            |
| 13 | 
                + "cn2an",  | 
            |
| 14 | 
                + "an2cn",  | 
            |
| 15 | 
                + "transform"  | 
            |
| 16 | 
                +]  | 
            
                @@ -0,0 +1,204 @@  | 
            ||
| 1 | 
                +from typing import Union  | 
            |
| 2 | 
                +from warnings import warn  | 
            |
| 3 | 
                +  | 
            |
| 4 | 
                +from proces import preprocess  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +from .conf import NUMBER_LOW_AN2CN, NUMBER_UP_AN2CN, UNIT_LOW_ORDER_AN2CN, UNIT_UP_ORDER_AN2CN  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +  | 
            |
| 9 | 
                +class An2Cn(object):  | 
            |
| 10 | 
                + def __init__(self) -> None:  | 
            |
| 11 | 
                + self.all_num = "0123456789"  | 
            |
| 12 | 
                + self.number_low = NUMBER_LOW_AN2CN  | 
            |
| 13 | 
                + self.number_up = NUMBER_UP_AN2CN  | 
            |
| 14 | 
                + self.mode_list = ["low", "up", "rmb", "direct"]  | 
            |
| 15 | 
                +  | 
            |
| 16 | 
                + def an2cn(self, inputs: Union[str, int, float] = None, mode: str = "low") -> str:  | 
            |
| 17 | 
                + """阿拉伯数字转中文数字  | 
            |
| 18 | 
                +  | 
            |
| 19 | 
                + :param inputs: 阿拉伯数字  | 
            |
| 20 | 
                + :param mode: low 小写数字,up 大写数字,rmb 人民币大写,direct 直接转化  | 
            |
| 21 | 
                + :return: 中文数字  | 
            |
| 22 | 
                + """  | 
            |
| 23 | 
                + if inputs is not None and inputs != "":  | 
            |
| 24 | 
                + if mode not in self.mode_list:  | 
            |
| 25 | 
                +                raise ValueError(f"mode 仅支持 {str(self.mode_list)} !")
               | 
            |
| 26 | 
                +  | 
            |
| 27 | 
                + # 将数字转化为字符串,这里会有Python会自动做转化  | 
            |
| 28 | 
                + # 1. -> 1.0 1.00 -> 1.0 -0 -> 0  | 
            |
| 29 | 
                + if not isinstance(inputs, str):  | 
            |
| 30 | 
                + inputs = self.__number_to_string(inputs)  | 
            |
| 31 | 
                +  | 
            |
| 32 | 
                + # 数据预处理:  | 
            |
| 33 | 
                + # 1. 繁体转简体  | 
            |
| 34 | 
                + # 2. 全角转半角  | 
            |
| 35 | 
                + inputs = preprocess(inputs, pipelines=[  | 
            |
| 36 | 
                + "traditional_to_simplified",  | 
            |
| 37 | 
                + "full_angle_to_half_angle"  | 
            |
| 38 | 
                + ])  | 
            |
| 39 | 
                +  | 
            |
| 40 | 
                + # 检查数据是否有效  | 
            |
| 41 | 
                + self.__check_inputs_is_valid(inputs)  | 
            |
| 42 | 
                +  | 
            |
| 43 | 
                + # 判断正负  | 
            |
| 44 | 
                + if inputs[0] == "-":  | 
            |
| 45 | 
                + sign = "负"  | 
            |
| 46 | 
                + inputs = inputs[1:]  | 
            |
| 47 | 
                + else:  | 
            |
| 48 | 
                + sign = ""  | 
            |
| 49 | 
                +  | 
            |
| 50 | 
                + if mode == "direct":  | 
            |
| 51 | 
                + output = self.__direct_convert(inputs)  | 
            |
| 52 | 
                + else:  | 
            |
| 53 | 
                + # 切割整数部分和小数部分  | 
            |
| 54 | 
                +                split_result = inputs.split(".")
               | 
            |
| 55 | 
                + len_split_result = len(split_result)  | 
            |
| 56 | 
                + if len_split_result == 1:  | 
            |
| 57 | 
                + # 不包含小数的输入  | 
            |
| 58 | 
                + integer_data = split_result[0]  | 
            |
| 59 | 
                + if mode == "rmb":  | 
            |
| 60 | 
                + output = self.__integer_convert(integer_data, "up") + "元整"  | 
            |
| 61 | 
                + else:  | 
            |
| 62 | 
                + output = self.__integer_convert(integer_data, mode)  | 
            |
| 63 | 
                + elif len_split_result == 2:  | 
            |
| 64 | 
                + # 包含小数的输入  | 
            |
| 65 | 
                + integer_data, decimal_data = split_result  | 
            |
| 66 | 
                + if mode == "rmb":  | 
            |
| 67 | 
                + int_data = self.__integer_convert(integer_data, "up")  | 
            |
| 68 | 
                + dec_data = self.__decimal_convert(decimal_data, "up")  | 
            |
| 69 | 
                + len_dec_data = len(dec_data)  | 
            |
| 70 | 
                +  | 
            |
| 71 | 
                + if len_dec_data == 0:  | 
            |
| 72 | 
                + output = int_data + "元整"  | 
            |
| 73 | 
                + elif len_dec_data == 1:  | 
            |
| 74 | 
                +                            raise ValueError(f"异常输出:{dec_data}")
               | 
            |
| 75 | 
                + elif len_dec_data == 2:  | 
            |
| 76 | 
                + if dec_data[1] != "零":  | 
            |
| 77 | 
                + if int_data == "零":  | 
            |
| 78 | 
                + output = dec_data[1] + "角"  | 
            |
| 79 | 
                + else:  | 
            |
| 80 | 
                + output = int_data + "元" + dec_data[1] + "角"  | 
            |
| 81 | 
                + else:  | 
            |
| 82 | 
                + output = int_data + "元整"  | 
            |
| 83 | 
                + else:  | 
            |
| 84 | 
                + if dec_data[1] != "零":  | 
            |
| 85 | 
                + if dec_data[2] != "零":  | 
            |
| 86 | 
                + if int_data == "零":  | 
            |
| 87 | 
                + output = dec_data[1] + "角" + dec_data[2] + "分"  | 
            |
| 88 | 
                + else:  | 
            |
| 89 | 
                + output = int_data + "元" + dec_data[1] + "角" + dec_data[2] + "分"  | 
            |
| 90 | 
                + else:  | 
            |
| 91 | 
                + if int_data == "零":  | 
            |
| 92 | 
                + output = dec_data[1] + "角"  | 
            |
| 93 | 
                + else:  | 
            |
| 94 | 
                + output = int_data + "元" + dec_data[1] + "角"  | 
            |
| 95 | 
                + else:  | 
            |
| 96 | 
                + if dec_data[2] != "零":  | 
            |
| 97 | 
                + if int_data == "零":  | 
            |
| 98 | 
                + output = dec_data[2] + "分"  | 
            |
| 99 | 
                + else:  | 
            |
| 100 | 
                + output = int_data + "元" + "零" + dec_data[2] + "分"  | 
            |
| 101 | 
                + else:  | 
            |
| 102 | 
                + output = int_data + "元整"  | 
            |
| 103 | 
                + else:  | 
            |
| 104 | 
                + output = self.__integer_convert(integer_data, mode) + self.__decimal_convert(decimal_data, mode)  | 
            |
| 105 | 
                + else:  | 
            |
| 106 | 
                +                    raise ValueError(f"输入格式错误:{inputs}!")
               | 
            |
| 107 | 
                + else:  | 
            |
| 108 | 
                +            raise ValueError("输入数据为空!")
               | 
            |
| 109 | 
                +  | 
            |
| 110 | 
                + return sign + output  | 
            |
| 111 | 
                +  | 
            |
| 112 | 
                + def __direct_convert(self, inputs: str) -> str:  | 
            |
| 113 | 
                + _output = ""  | 
            |
| 114 | 
                + for d in inputs:  | 
            |
| 115 | 
                + if d == ".":  | 
            |
| 116 | 
                + _output += "点"  | 
            |
| 117 | 
                + else:  | 
            |
| 118 | 
                + _output += self.number_low[int(d)]  | 
            |
| 119 | 
                + return _output  | 
            |
| 120 | 
                +  | 
            |
| 121 | 
                + @staticmethod  | 
            |
| 122 | 
                + def __number_to_string(number_data: Union[int, float]) -> str:  | 
            |
| 123 | 
                + # 小数处理:python 会自动把 0.00005 转化成 5e-05,因此 str(0.00005) != "0.00005"  | 
            |
| 124 | 
                + string_data = str(number_data)  | 
            |
| 125 | 
                + if "e" in string_data:  | 
            |
| 126 | 
                +            string_data_list = string_data.split("e")
               | 
            |
| 127 | 
                + string_key = string_data_list[0]  | 
            |
| 128 | 
                + string_value = string_data_list[1]  | 
            |
| 129 | 
                + if string_value[0] == "-":  | 
            |
| 130 | 
                + string_data = "0." + "0" * (int(string_value[1:]) - 1) + string_key  | 
            |
| 131 | 
                + else:  | 
            |
| 132 | 
                + string_data = string_key + "0" * int(string_value)  | 
            |
| 133 | 
                + return string_data  | 
            |
| 134 | 
                +  | 
            |
| 135 | 
                + def __check_inputs_is_valid(self, check_data: str) -> None:  | 
            |
| 136 | 
                + # 检查输入数据是否在规定的字典中  | 
            |
| 137 | 
                + all_check_keys = self.all_num + ".-"  | 
            |
| 138 | 
                + for data in check_data:  | 
            |
| 139 | 
                + if data not in all_check_keys:  | 
            |
| 140 | 
                +                raise ValueError(f"输入的数据不在转化范围内:{data}!")
               | 
            |
| 141 | 
                +  | 
            |
| 142 | 
                + def __integer_convert(self, integer_data: str, mode: str) -> str:  | 
            |
| 143 | 
                + if mode == "low":  | 
            |
| 144 | 
                + numeral_list = NUMBER_LOW_AN2CN  | 
            |
| 145 | 
                + unit_list = UNIT_LOW_ORDER_AN2CN  | 
            |
| 146 | 
                + elif mode == "up":  | 
            |
| 147 | 
                + numeral_list = NUMBER_UP_AN2CN  | 
            |
| 148 | 
                + unit_list = UNIT_UP_ORDER_AN2CN  | 
            |
| 149 | 
                + else:  | 
            |
| 150 | 
                +            raise ValueError(f"error mode: {mode}")
               | 
            |
| 151 | 
                +  | 
            |
| 152 | 
                + # 去除前面的 0,比如 007 => 7  | 
            |
| 153 | 
                + integer_data = str(int(integer_data))  | 
            |
| 154 | 
                +  | 
            |
| 155 | 
                + len_integer_data = len(integer_data)  | 
            |
| 156 | 
                + if len_integer_data > len(unit_list):  | 
            |
| 157 | 
                +            raise ValueError(f"超出数据范围,最长支持 {len(unit_list)} 位")
               | 
            |
| 158 | 
                +  | 
            |
| 159 | 
                + output_an = ""  | 
            |
| 160 | 
                + for i, d in enumerate(integer_data):  | 
            |
| 161 | 
                + if int(d):  | 
            |
| 162 | 
                + output_an += numeral_list[int(d)] + unit_list[len_integer_data - i - 1]  | 
            |
| 163 | 
                + else:  | 
            |
| 164 | 
                + if not (len_integer_data - i - 1) % 4:  | 
            |
| 165 | 
                + output_an += numeral_list[int(d)] + unit_list[len_integer_data - i - 1]  | 
            |
| 166 | 
                +  | 
            |
| 167 | 
                + if i > 0 and not output_an[-1] == "零":  | 
            |
| 168 | 
                + output_an += numeral_list[int(d)]  | 
            |
| 169 | 
                +  | 
            |
| 170 | 
                +        output_an = output_an.replace("零零", "零").replace("零万", "万").replace("零亿", "亿").replace("亿万", "亿") \
               | 
            |
| 171 | 
                +            .strip("零")
               | 
            |
| 172 | 
                +  | 
            |
| 173 | 
                + # 解决「一十几」问题  | 
            |
| 174 | 
                + if output_an[:2] in ["一十"]:  | 
            |
| 175 | 
                + output_an = output_an[1:]  | 
            |
| 176 | 
                +  | 
            |
| 177 | 
                + # 0 - 1 之间的小数  | 
            |
| 178 | 
                + if not output_an:  | 
            |
| 179 | 
                + output_an = "零"  | 
            |
| 180 | 
                +  | 
            |
| 181 | 
                + return output_an  | 
            |
| 182 | 
                +  | 
            |
| 183 | 
                + def __decimal_convert(self, decimal_data: str, o_mode: str) -> str:  | 
            |
| 184 | 
                + len_decimal_data = len(decimal_data)  | 
            |
| 185 | 
                +  | 
            |
| 186 | 
                + if len_decimal_data > 16:  | 
            |
| 187 | 
                +            warn(f"注意:小数部分长度为 {len_decimal_data} ,将自动截取前 16 位有效精度!")
               | 
            |
| 188 | 
                + decimal_data = decimal_data[:16]  | 
            |
| 189 | 
                +  | 
            |
| 190 | 
                + if len_decimal_data:  | 
            |
| 191 | 
                + output_an = "点"  | 
            |
| 192 | 
                + else:  | 
            |
| 193 | 
                + output_an = ""  | 
            |
| 194 | 
                +  | 
            |
| 195 | 
                + if o_mode == "low":  | 
            |
| 196 | 
                + numeral_list = NUMBER_LOW_AN2CN  | 
            |
| 197 | 
                + elif o_mode == "up":  | 
            |
| 198 | 
                + numeral_list = NUMBER_UP_AN2CN  | 
            |
| 199 | 
                + else:  | 
            |
| 200 | 
                +            raise ValueError(f"error mode: {o_mode}")
               | 
            |
| 201 | 
                +  | 
            |
| 202 | 
                + for data in decimal_data:  | 
            |
| 203 | 
                + output_an += numeral_list[int(data)]  | 
            |
| 204 | 
                + return output_an  | 
            
                @@ -0,0 +1,71 @@  | 
            ||
| 1 | 
                +import unittest  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from .an2cn import An2Cn  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +class An2CnTest(unittest.TestCase):  | 
            |
| 7 | 
                + def setUp(self) -> None:  | 
            |
| 8 | 
                +        self.input_data = {
               | 
            |
| 9 | 
                + 0: ["零", "零", "零元整", "零"],  | 
            |
| 10 | 
                + 1: ["一", "壹", "壹元整", "一"],  | 
            |
| 11 | 
                + 11: ["十一", "壹拾壹", "壹拾壹元整", "一一"],  | 
            |
| 12 | 
                + 1000000: ["一百万", "壹佰万", "壹佰万元整", "一零零零零零零"],  | 
            |
| 13 | 
                + 1000054: ["一百万零五十四", "壹佰万零伍拾肆", "壹佰万零伍拾肆元整", "一零零零零五四"],  | 
            |
| 14 | 
                + 31000054: ["三千一百万零五十四", "叁仟壹佰万零伍拾肆", "叁仟壹佰万零伍拾肆元整", "三一零零零零五四"],  | 
            |
| 15 | 
                + 9876543298765432: [  | 
            |
| 16 | 
                + "九千八百七十六万五千四百三十二亿九千八百七十六万五千四百三十二",  | 
            |
| 17 | 
                + "玖仟捌佰柒拾陆万伍仟肆佰叁拾贰亿玖仟捌佰柒拾陆万伍仟肆佰叁拾贰",  | 
            |
| 18 | 
                + "玖仟捌佰柒拾陆万伍仟肆佰叁拾贰亿玖仟捌佰柒拾陆万伍仟肆佰叁拾贰元整",  | 
            |
| 19 | 
                + "九八七六五四三二九八七六五四三二"  | 
            |
| 20 | 
                + ],  | 
            |
| 21 | 
                + 10000000000000: ["十万亿", "壹拾万亿", "壹拾万亿元整", "一零零零零零零零零零零零零零"],  | 
            |
| 22 | 
                + -0: ["零", "零", "零元整", "零"],  | 
            |
| 23 | 
                + -1: ["负一", "负壹", "负壹元整", "负一"],  | 
            |
| 24 | 
                + -11: ["负十一", "负壹拾壹", "负壹拾壹元整", "负一一"],  | 
            |
| 25 | 
                + 0.000500050005005: [  | 
            |
| 26 | 
                + "零点零零零五零零零五零零零五零零五",  | 
            |
| 27 | 
                + "零点零零零伍零零零伍零零零伍零零伍",  | 
            |
| 28 | 
                + "零元整",  | 
            |
| 29 | 
                + "零点零零零五零零零五零零零五零零五"  | 
            |
| 30 | 
                + ],  | 
            |
| 31 | 
                + 0.00005: ["零点零零零零五", "零点零零零零伍", "零元整", "零点零零零零五"],  | 
            |
| 32 | 
                + 0.4321: ["零点四三二一", "零点肆叁贰壹", "肆角叁分", "零点四三二一"],  | 
            |
| 33 | 
                + 1000054.4321: [  | 
            |
| 34 | 
                + "一百万零五十四点四三二一",  | 
            |
| 35 | 
                + "壹佰万零伍拾肆点肆叁贰壹",  | 
            |
| 36 | 
                + "壹佰万零伍拾肆元肆角叁分",  | 
            |
| 37 | 
                + "一零零零零五四点四三二一"  | 
            |
| 38 | 
                + ],  | 
            |
| 39 | 
                + 1.01: ["一点零一", "壹点零壹", "壹元零壹分", "一点零一"],  | 
            |
| 40 | 
                + 1.2: ["一点二", "壹点贰", "壹元贰角", "一点二"],  | 
            |
| 41 | 
                + 0.01: ["零点零一", "零点零壹", "壹分", "零点零一"],  | 
            |
| 42 | 
                + -0.1: ["负零点一", "负零点壹", "负壹角", "负零点一"],  | 
            |
| 43 | 
                + -0: ["零", "零", "零元整", "零"],  | 
            |
| 44 | 
                + 1.10: ["一点一", "壹点壹", "壹元壹角", "一点一"],  | 
            |
| 45 | 
                + 12.0: ["十二点零", "壹拾贰点零", "壹拾贰元整", "一二点零"],  | 
            |
| 46 | 
                + 2.0: ["二点零", "贰点零", "贰元整", "二点零"],  | 
            |
| 47 | 
                + 0.10: ["零点一", "零点壹", "壹角", "零点一"]  | 
            |
| 48 | 
                + }  | 
            |
| 49 | 
                +  | 
            |
| 50 | 
                + self.error_input_data = [  | 
            |
| 51 | 
                + "123.1.1",  | 
            |
| 52 | 
                + "0.1零"  | 
            |
| 53 | 
                + ]  | 
            |
| 54 | 
                +  | 
            |
| 55 | 
                + self.ac = An2Cn()  | 
            |
| 56 | 
                +  | 
            |
| 57 | 
                + def test_an2cn(self) -> None:  | 
            |
| 58 | 
                + for item in self.input_data.keys():  | 
            |
| 59 | 
                + self.assertEqual(self.ac.an2cn(item), self.input_data[item][0])  | 
            |
| 60 | 
                + self.assertEqual(self.ac.an2cn(item, "low"), self.input_data[item][0])  | 
            |
| 61 | 
                + self.assertEqual(self.ac.an2cn(item, "up"), self.input_data[item][1])  | 
            |
| 62 | 
                + self.assertEqual(self.ac.an2cn(item, "rmb"), self.input_data[item][2])  | 
            |
| 63 | 
                + self.assertEqual(self.ac.an2cn(item, "direct"), self.input_data[item][3])  | 
            |
| 64 | 
                +  | 
            |
| 65 | 
                + with self.assertRaises(ValueError):  | 
            |
| 66 | 
                + for error_data in self.error_input_data:  | 
            |
| 67 | 
                + self.ac.an2cn(error_data)  | 
            |
| 68 | 
                +  | 
            |
| 69 | 
                +  | 
            |
| 70 | 
                +if __name__ == '__main__':  | 
            |
| 71 | 
                + unittest.main()  | 
            
                @@ -0,0 +1,294 @@  | 
            ||
| 1 | 
                +import re  | 
            |
| 2 | 
                +from warnings import warn  | 
            |
| 3 | 
                +from typing import Union  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +from proces import preprocess  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +from .an2cn import An2Cn  | 
            |
| 8 | 
                +from .conf import NUMBER_CN2AN, UNIT_CN2AN, STRICT_CN_NUMBER, NORMAL_CN_NUMBER, NUMBER_LOW_AN2CN, UNIT_LOW_AN2CN  | 
            |
| 9 | 
                +  | 
            |
| 10 | 
                +  | 
            |
| 11 | 
                +class Cn2An(object):  | 
            |
| 12 | 
                + def __init__(self) -> None:  | 
            |
| 13 | 
                + self.all_num = "".join(list(NUMBER_CN2AN.keys()))  | 
            |
| 14 | 
                + self.all_unit = "".join(list(UNIT_CN2AN.keys()))  | 
            |
| 15 | 
                + self.strict_cn_number = STRICT_CN_NUMBER  | 
            |
| 16 | 
                + self.normal_cn_number = NORMAL_CN_NUMBER  | 
            |
| 17 | 
                +        self.check_key_dict = {
               | 
            |
| 18 | 
                + "strict": "".join(self.strict_cn_number.values()) + "点负",  | 
            |
| 19 | 
                + "normal": "".join(self.normal_cn_number.values()) + "点负",  | 
            |
| 20 | 
                + "smart": "".join(self.normal_cn_number.values()) + "点负" + "01234567890.-"  | 
            |
| 21 | 
                + }  | 
            |
| 22 | 
                + self.pattern_dict = self.__get_pattern()  | 
            |
| 23 | 
                + self.ac = An2Cn()  | 
            |
| 24 | 
                + self.mode_list = ["strict", "normal", "smart"]  | 
            |
| 25 | 
                +        self.yjf_pattern = re.compile(fr"^.*?[元圆][{self.all_num}]角([{self.all_num}]分)?$")
               | 
            |
| 26 | 
                +        self.pattern1 = re.compile(fr"^-?\d+(\.\d+)?[{self.all_unit}]?$")
               | 
            |
| 27 | 
                +        self.ptn_all_num = re.compile(f"^[{self.all_num}]+$")
               | 
            |
| 28 | 
                + # "十?" is for special case "十一万三"  | 
            |
| 29 | 
                +        self.ptn_speaking_mode = re.compile(f"^([{self.all_num}]{{0,2}}[{self.all_unit}])+[{self.all_num}]$")
               | 
            |
| 30 | 
                +  | 
            |
| 31 | 
                + def cn2an(self, inputs: Union[str, int, float] = None, mode: str = "strict") -> Union[float, int]:  | 
            |
| 32 | 
                + """中文数字转阿拉伯数字  | 
            |
| 33 | 
                +  | 
            |
| 34 | 
                + :param inputs: 中文数字、阿拉伯数字、中文数字和阿拉伯数字  | 
            |
| 35 | 
                + :param mode: strict 严格,normal 正常,smart 智能  | 
            |
| 36 | 
                + :return: 阿拉伯数字  | 
            |
| 37 | 
                + """  | 
            |
| 38 | 
                + if inputs is not None or inputs == "":  | 
            |
| 39 | 
                + if mode not in self.mode_list:  | 
            |
| 40 | 
                +                raise ValueError(f"mode 仅支持 {str(self.mode_list)} !")
               | 
            |
| 41 | 
                +  | 
            |
| 42 | 
                + # 将数字转化为字符串  | 
            |
| 43 | 
                + if not isinstance(inputs, str):  | 
            |
| 44 | 
                + inputs = str(inputs)  | 
            |
| 45 | 
                +  | 
            |
| 46 | 
                + # 数据预处理:  | 
            |
| 47 | 
                + # 1. 繁体转简体  | 
            |
| 48 | 
                + # 2. 全角转半角  | 
            |
| 49 | 
                + inputs = preprocess(inputs, pipelines=[  | 
            |
| 50 | 
                + "traditional_to_simplified",  | 
            |
| 51 | 
                + "full_angle_to_half_angle"  | 
            |
| 52 | 
                + ])  | 
            |
| 53 | 
                +  | 
            |
| 54 | 
                + # 特殊转化 廿  | 
            |
| 55 | 
                +            inputs = inputs.replace("廿", "二十")
               | 
            |
| 56 | 
                +  | 
            |
| 57 | 
                + # 检查输入数据是否有效  | 
            |
| 58 | 
                + sign, integer_data, decimal_data, is_all_num = self.__check_input_data_is_valid(inputs, mode)  | 
            |
| 59 | 
                +  | 
            |
| 60 | 
                + # smart 下的特殊情况  | 
            |
| 61 | 
                + if sign == 0:  | 
            |
| 62 | 
                + return integer_data  | 
            |
| 63 | 
                + else:  | 
            |
| 64 | 
                + if not is_all_num:  | 
            |
| 65 | 
                + if decimal_data is None:  | 
            |
| 66 | 
                + output = self.__integer_convert(integer_data)  | 
            |
| 67 | 
                + else:  | 
            |
| 68 | 
                + output = self.__integer_convert(integer_data) + self.__decimal_convert(decimal_data)  | 
            |
| 69 | 
                + # fix 1 + 0.57 = 1.5699999999999998  | 
            |
| 70 | 
                + output = round(output, len(decimal_data))  | 
            |
| 71 | 
                + else:  | 
            |
| 72 | 
                + if decimal_data is None:  | 
            |
| 73 | 
                + output = self.__direct_convert(integer_data)  | 
            |
| 74 | 
                + else:  | 
            |
| 75 | 
                + output = self.__direct_convert(integer_data) + self.__decimal_convert(decimal_data)  | 
            |
| 76 | 
                + # fix 1 + 0.57 = 1.5699999999999998  | 
            |
| 77 | 
                + output = round(output, len(decimal_data))  | 
            |
| 78 | 
                + else:  | 
            |
| 79 | 
                +            raise ValueError("输入数据为空!")
               | 
            |
| 80 | 
                +  | 
            |
| 81 | 
                + return sign * output  | 
            |
| 82 | 
                +  | 
            |
| 83 | 
                + def __get_pattern(self) -> dict:  | 
            |
| 84 | 
                + # 整数严格检查  | 
            |
| 85 | 
                + _0 = "[零]"  | 
            |
| 86 | 
                + _1_9 = "[一二三四五六七八九]"  | 
            |
| 87 | 
                +        _10_99 = f"{_1_9}?[十]{_1_9}?"
               | 
            |
| 88 | 
                +        _1_99 = f"({_10_99}|{_1_9})"
               | 
            |
| 89 | 
                +        _100_999 = f"({_1_9}[百]([零]{_1_9})?|{_1_9}[百]{_10_99})"
               | 
            |
| 90 | 
                +        _1_999 = f"({_100_999}|{_1_99})"
               | 
            |
| 91 | 
                +        _1000_9999 = f"({_1_9}[千]([零]{_1_99})?|{_1_9}[千]{_100_999})"
               | 
            |
| 92 | 
                +        _1_9999 = f"({_1000_9999}|{_1_999})"
               | 
            |
| 93 | 
                +        _10000_99999999 = f"({_1_9999}[万]([零]{_1_999})?|{_1_9999}[万]{_1000_9999})"
               | 
            |
| 94 | 
                +        _1_99999999 = f"({_10000_99999999}|{_1_9999})"
               | 
            |
| 95 | 
                +        _100000000_9999999999999999 = f"({_1_99999999}[亿]([零]{_1_99999999})?|{_1_99999999}[亿]{_10000_99999999})"
               | 
            |
| 96 | 
                +        _1_9999999999999999 = f"({_100000000_9999999999999999}|{_1_99999999})"
               | 
            |
| 97 | 
                +        str_int_pattern = f"^({_0}|{_1_9999999999999999})$"
               | 
            |
| 98 | 
                +        nor_int_pattern = f"^({_0}|{_1_9999999999999999})$"
               | 
            |
| 99 | 
                +  | 
            |
| 100 | 
                +        str_dec_pattern = "^[零一二三四五六七八九]{0,15}[一二三四五六七八九]$"
               | 
            |
| 101 | 
                +        nor_dec_pattern = "^[零一二三四五六七八九]{0,16}$"
               | 
            |
| 102 | 
                +  | 
            |
| 103 | 
                + for str_num in self.strict_cn_number.keys():  | 
            |
| 104 | 
                + str_int_pattern = str_int_pattern.replace(str_num, self.strict_cn_number[str_num])  | 
            |
| 105 | 
                + str_dec_pattern = str_dec_pattern.replace(str_num, self.strict_cn_number[str_num])  | 
            |
| 106 | 
                + for nor_num in self.normal_cn_number.keys():  | 
            |
| 107 | 
                + nor_int_pattern = nor_int_pattern.replace(nor_num, self.normal_cn_number[nor_num])  | 
            |
| 108 | 
                + nor_dec_pattern = nor_dec_pattern.replace(nor_num, self.normal_cn_number[nor_num])  | 
            |
| 109 | 
                +  | 
            |
| 110 | 
                +        pattern_dict = {
               | 
            |
| 111 | 
                +            "strict": {
               | 
            |
| 112 | 
                + "int": re.compile(str_int_pattern),  | 
            |
| 113 | 
                + "dec": re.compile(str_dec_pattern)  | 
            |
| 114 | 
                + },  | 
            |
| 115 | 
                +            "normal": {
               | 
            |
| 116 | 
                + "int": re.compile(nor_int_pattern),  | 
            |
| 117 | 
                + "dec": re.compile(nor_dec_pattern)  | 
            |
| 118 | 
                + }  | 
            |
| 119 | 
                + }  | 
            |
| 120 | 
                + return pattern_dict  | 
            |
| 121 | 
                +  | 
            |
| 122 | 
                + def __copy_num(self, num):  | 
            |
| 123 | 
                + cn_num = ""  | 
            |
| 124 | 
                + for n in num:  | 
            |
| 125 | 
                + cn_num += NUMBER_LOW_AN2CN[int(n)]  | 
            |
| 126 | 
                + return cn_num  | 
            |
| 127 | 
                +  | 
            |
| 128 | 
                + def __check_input_data_is_valid(self, check_data: str, mode: str) -> (int, str, str, bool):  | 
            |
| 129 | 
                + # 去除 元整、圆整、元正、圆正  | 
            |
| 130 | 
                + stop_words = ["元整", "圆整", "元正", "圆正"]  | 
            |
| 131 | 
                + for word in stop_words:  | 
            |
| 132 | 
                + if check_data[-2:] == word:  | 
            |
| 133 | 
                + check_data = check_data[:-2]  | 
            |
| 134 | 
                +  | 
            |
| 135 | 
                + # 去除 元、圆  | 
            |
| 136 | 
                + if mode != "strict":  | 
            |
| 137 | 
                + normal_stop_words = ["圆", "元"]  | 
            |
| 138 | 
                + for word in normal_stop_words:  | 
            |
| 139 | 
                + if check_data[-1] == word:  | 
            |
| 140 | 
                + check_data = check_data[:-1]  | 
            |
| 141 | 
                +  | 
            |
| 142 | 
                + # 处理元角分  | 
            |
| 143 | 
                + result = self.yjf_pattern.search(check_data)  | 
            |
| 144 | 
                + if result:  | 
            |
| 145 | 
                +            check_data = check_data.replace("元", "点").replace("角", "").replace("分", "")
               | 
            |
| 146 | 
                +  | 
            |
| 147 | 
                + # 处理特殊问法:一千零十一 一万零百一十一  | 
            |
| 148 | 
                + if "零十" in check_data:  | 
            |
| 149 | 
                +            check_data = check_data.replace("零十", "零一十")
               | 
            |
| 150 | 
                + if "零百" in check_data:  | 
            |
| 151 | 
                +            check_data = check_data.replace("零百", "零一百")
               | 
            |
| 152 | 
                +  | 
            |
| 153 | 
                + for data in check_data:  | 
            |
| 154 | 
                + if data not in self.check_key_dict[mode]:  | 
            |
| 155 | 
                +                raise ValueError(f"当前为{mode}模式,输入的数据不在转化范围内:{data}!")
               | 
            |
| 156 | 
                +  | 
            |
| 157 | 
                + # 确定正负号  | 
            |
| 158 | 
                + if check_data[0] == "负":  | 
            |
| 159 | 
                + check_data = check_data[1:]  | 
            |
| 160 | 
                + sign = -1  | 
            |
| 161 | 
                + else:  | 
            |
| 162 | 
                + sign = 1  | 
            |
| 163 | 
                +  | 
            |
| 164 | 
                + if "点" in check_data:  | 
            |
| 165 | 
                +            split_data = check_data.split("点")
               | 
            |
| 166 | 
                + if len(split_data) == 2:  | 
            |
| 167 | 
                + integer_data, decimal_data = split_data  | 
            |
| 168 | 
                + # 将 smart 模式中的阿拉伯数字转化成中文数字  | 
            |
| 169 | 
                + if mode == "smart":  | 
            |
| 170 | 
                + integer_data = re.sub(r"\d+", lambda x: self.ac.an2cn(x.group()), integer_data)  | 
            |
| 171 | 
                + decimal_data = re.sub(r"\d+", lambda x: self.__copy_num(x.group()), decimal_data)  | 
            |
| 172 | 
                + mode = "normal"  | 
            |
| 173 | 
                + else:  | 
            |
| 174 | 
                +                raise ValueError("数据中包含不止一个点!")
               | 
            |
| 175 | 
                + else:  | 
            |
| 176 | 
                + integer_data = check_data  | 
            |
| 177 | 
                + decimal_data = None  | 
            |
| 178 | 
                + # 将 smart 模式中的阿拉伯数字转化成中文数字  | 
            |
| 179 | 
                + if mode == "smart":  | 
            |
| 180 | 
                + # 10.1万 10.1  | 
            |
| 181 | 
                + result1 = self.pattern1.search(integer_data)  | 
            |
| 182 | 
                + if result1:  | 
            |
| 183 | 
                + if result1.group() == integer_data:  | 
            |
| 184 | 
                + if integer_data[-1] in UNIT_CN2AN.keys():  | 
            |
| 185 | 
                + output = int(float(integer_data[:-1]) * UNIT_CN2AN[integer_data[-1]])  | 
            |
| 186 | 
                + else:  | 
            |
| 187 | 
                + output = float(integer_data)  | 
            |
| 188 | 
                + return 0, output, None, None  | 
            |
| 189 | 
                +  | 
            |
| 190 | 
                + integer_data = re.sub(r"\d+", lambda x: self.ac.an2cn(x.group()), integer_data)  | 
            |
| 191 | 
                + mode = "normal"  | 
            |
| 192 | 
                +  | 
            |
| 193 | 
                + result_int = self.pattern_dict[mode]["int"].search(integer_data)  | 
            |
| 194 | 
                + if result_int:  | 
            |
| 195 | 
                + if result_int.group() == integer_data:  | 
            |
| 196 | 
                + if decimal_data is not None:  | 
            |
| 197 | 
                + result_dec = self.pattern_dict[mode]["dec"].search(decimal_data)  | 
            |
| 198 | 
                + if result_dec:  | 
            |
| 199 | 
                + if result_dec.group() == decimal_data:  | 
            |
| 200 | 
                + return sign, integer_data, decimal_data, False  | 
            |
| 201 | 
                + else:  | 
            |
| 202 | 
                + return sign, integer_data, decimal_data, False  | 
            |
| 203 | 
                + else:  | 
            |
| 204 | 
                + if mode == "strict":  | 
            |
| 205 | 
                +                raise ValueError(f"不符合格式的数据:{integer_data}")
               | 
            |
| 206 | 
                + elif mode == "normal":  | 
            |
| 207 | 
                + # 纯数模式:一二三  | 
            |
| 208 | 
                + result_all_num = self.ptn_all_num.search(integer_data)  | 
            |
| 209 | 
                + if result_all_num:  | 
            |
| 210 | 
                + if result_all_num.group() == integer_data:  | 
            |
| 211 | 
                + if decimal_data is not None:  | 
            |
| 212 | 
                + result_dec = self.pattern_dict[mode]["dec"].search(decimal_data)  | 
            |
| 213 | 
                + if result_dec:  | 
            |
| 214 | 
                + if result_dec.group() == decimal_data:  | 
            |
| 215 | 
                + return sign, integer_data, decimal_data, True  | 
            |
| 216 | 
                + else:  | 
            |
| 217 | 
                + return sign, integer_data, decimal_data, True  | 
            |
| 218 | 
                +  | 
            |
| 219 | 
                + # 口语模式:一万二,两千三,三百四,十三万六,一百二十五万三  | 
            |
| 220 | 
                + result_speaking_mode = self.ptn_speaking_mode.search(integer_data)  | 
            |
| 221 | 
                + if len(integer_data) >= 3 and result_speaking_mode and result_speaking_mode.group() == integer_data:  | 
            |
| 222 | 
                + # len(integer_data)>=3: because the minimum length of integer_data that can be matched is 3  | 
            |
| 223 | 
                + # to find the last unit  | 
            |
| 224 | 
                + last_unit = result_speaking_mode.groups()[-1][-1]  | 
            |
| 225 | 
                + _unit = UNIT_LOW_AN2CN[UNIT_CN2AN[last_unit] // 10]  | 
            |
| 226 | 
                + integer_data = integer_data + _unit  | 
            |
| 227 | 
                + if decimal_data is not None:  | 
            |
| 228 | 
                + result_dec = self.pattern_dict[mode]["dec"].search(decimal_data)  | 
            |
| 229 | 
                + if result_dec:  | 
            |
| 230 | 
                + if result_dec.group() == decimal_data:  | 
            |
| 231 | 
                + return sign, integer_data, decimal_data, False  | 
            |
| 232 | 
                + else:  | 
            |
| 233 | 
                + return sign, integer_data, decimal_data, False  | 
            |
| 234 | 
                +  | 
            |
| 235 | 
                +        raise ValueError(f"不符合格式的数据:{check_data}")
               | 
            |
| 236 | 
                +  | 
            |
| 237 | 
                + def __integer_convert(self, integer_data: str) -> int:  | 
            |
| 238 | 
                + # 核心  | 
            |
| 239 | 
                + output_integer = 0  | 
            |
| 240 | 
                + unit = 1  | 
            |
| 241 | 
                + ten_thousand_unit = 1  | 
            |
| 242 | 
                + for index, cn_num in enumerate(reversed(integer_data)):  | 
            |
| 243 | 
                + # 数值  | 
            |
| 244 | 
                + if cn_num in NUMBER_CN2AN:  | 
            |
| 245 | 
                + num = NUMBER_CN2AN[cn_num]  | 
            |
| 246 | 
                + output_integer += num * unit  | 
            |
| 247 | 
                + # 单位  | 
            |
| 248 | 
                + elif cn_num in UNIT_CN2AN:  | 
            |
| 249 | 
                + unit = UNIT_CN2AN[cn_num]  | 
            |
| 250 | 
                + # 判断出万、亿、万亿  | 
            |
| 251 | 
                + if unit % 10000 == 0:  | 
            |
| 252 | 
                + # 万 亿  | 
            |
| 253 | 
                + if unit > ten_thousand_unit:  | 
            |
| 254 | 
                + ten_thousand_unit = unit  | 
            |
| 255 | 
                + # 万亿  | 
            |
| 256 | 
                + else:  | 
            |
| 257 | 
                + ten_thousand_unit = unit * ten_thousand_unit  | 
            |
| 258 | 
                + unit = ten_thousand_unit  | 
            |
| 259 | 
                +  | 
            |
| 260 | 
                + if unit < ten_thousand_unit:  | 
            |
| 261 | 
                + unit = unit * ten_thousand_unit  | 
            |
| 262 | 
                +  | 
            |
| 263 | 
                + if index == len(integer_data) - 1:  | 
            |
| 264 | 
                + output_integer += unit  | 
            |
| 265 | 
                + else:  | 
            |
| 266 | 
                +                raise ValueError(f"{cn_num} 不在转化范围内")
               | 
            |
| 267 | 
                +  | 
            |
| 268 | 
                + return int(output_integer)  | 
            |
| 269 | 
                +  | 
            |
| 270 | 
                + def __decimal_convert(self, decimal_data: str) -> float:  | 
            |
| 271 | 
                + len_decimal_data = len(decimal_data)  | 
            |
| 272 | 
                +  | 
            |
| 273 | 
                + if len_decimal_data > 16:  | 
            |
| 274 | 
                +            warn(f"注意:小数部分长度为 {len_decimal_data} ,将自动截取前 16 位有效精度!")
               | 
            |
| 275 | 
                + decimal_data = decimal_data[:16]  | 
            |
| 276 | 
                + len_decimal_data = 16  | 
            |
| 277 | 
                +  | 
            |
| 278 | 
                + output_decimal = 0  | 
            |
| 279 | 
                + for index in range(len(decimal_data) - 1, -1, -1):  | 
            |
| 280 | 
                + unit_key = NUMBER_CN2AN[decimal_data[index]]  | 
            |
| 281 | 
                + output_decimal += unit_key * 10 ** -(index + 1)  | 
            |
| 282 | 
                +  | 
            |
| 283 | 
                + # 处理精度溢出问题  | 
            |
| 284 | 
                + output_decimal = round(output_decimal, len_decimal_data)  | 
            |
| 285 | 
                +  | 
            |
| 286 | 
                + return output_decimal  | 
            |
| 287 | 
                +  | 
            |
| 288 | 
                + def __direct_convert(self, data: str) -> int:  | 
            |
| 289 | 
                + output_data = 0  | 
            |
| 290 | 
                + for index in range(len(data) - 1, -1, -1):  | 
            |
| 291 | 
                + unit_key = NUMBER_CN2AN[data[index]]  | 
            |
| 292 | 
                + output_data += unit_key * 10 ** (len(data) - index - 1)  | 
            |
| 293 | 
                +  | 
            |
| 294 | 
                + return output_data  | 
            
                @@ -0,0 +1,215 @@  | 
            ||
| 1 | 
                +import unittest  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from .cn2an import Cn2An  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +class Cn2anTest(unittest.TestCase):  | 
            |
| 7 | 
                + def setUp(self) -> None:  | 
            |
| 8 | 
                +        self.strict_data_dict = {
               | 
            |
| 9 | 
                + "零": 0,  | 
            |
| 10 | 
                + "一": 1,  | 
            |
| 11 | 
                + "十": 10,  | 
            |
| 12 | 
                + "十一": 11,  | 
            |
| 13 | 
                + "一十一": 11,  | 
            |
| 14 | 
                + "二十": 20,  | 
            |
| 15 | 
                + "二十一": 21,  | 
            |
| 16 | 
                + "一百": 100,  | 
            |
| 17 | 
                + "一百零一": 101,  | 
            |
| 18 | 
                + "一百一十": 110,  | 
            |
| 19 | 
                + "一百一十一": 111,  | 
            |
| 20 | 
                + "一千": 1000,  | 
            |
| 21 | 
                + "一千一百": 1100,  | 
            |
| 22 | 
                + "一千一百一十": 1110,  | 
            |
| 23 | 
                + "一千一百一十一": 1111,  | 
            |
| 24 | 
                + "一千零一十": 1010,  | 
            |
| 25 | 
                + "一千零十": 1010,  | 
            |
| 26 | 
                + "一千零十一": 1011,  | 
            |
| 27 | 
                + "一千零一十一": 1011,  | 
            |
| 28 | 
                + "一千零一": 1001,  | 
            |
| 29 | 
                + "一千一百零一": 1101,  | 
            |
| 30 | 
                + "一万一千一百一十一": 11111,  | 
            |
| 31 | 
                + "一十一万一千一百一十一": 111111,  | 
            |
| 32 | 
                + "一百一十一万一千一百一十一": 1111111,  | 
            |
| 33 | 
                + "一千一百一十一万一千一百一十一": 11111111,  | 
            |
| 34 | 
                + "一亿一千一百一十一万一千一百一十一": 111111111,  | 
            |
| 35 | 
                + "一十一亿一千一百一十一万一千一百一十一": 1111111111,  | 
            |
| 36 | 
                + "一百一十一亿一千一百一十一万一千一百一十一": 11111111111,  | 
            |
| 37 | 
                + "一千一百一十一亿一千一百一十一万一千一百一十一": 111111111111,  | 
            |
| 38 | 
                + "一千一百一十一万一千一百一十一亿一千一百一十一万一千一百一十一": 1111111111111111,  | 
            |
| 39 | 
                + "壹": 1,  | 
            |
| 40 | 
                + "拾": 10,  | 
            |
| 41 | 
                + "拾壹": 11,  | 
            |
| 42 | 
                + "壹拾壹": 11,  | 
            |
| 43 | 
                + "壹佰壹拾壹": 111,  | 
            |
| 44 | 
                + "壹仟壹佰壹拾壹": 1111,  | 
            |
| 45 | 
                + "壹万壹仟壹佰壹拾壹": 11111,  | 
            |
| 46 | 
                + "壹拾壹万壹仟壹佰壹拾壹": 111111,  | 
            |
| 47 | 
                + "壹佰壹拾壹万壹仟壹佰壹拾壹": 1111111,  | 
            |
| 48 | 
                + "壹仟壹佰壹拾壹万壹仟壹佰壹拾壹": 11111111,  | 
            |
| 49 | 
                + "壹亿壹仟壹佰壹拾壹万壹仟壹佰壹拾壹": 111111111,  | 
            |
| 50 | 
                + "壹拾壹亿壹仟壹佰壹拾壹万壹仟壹佰壹拾壹": 1111111111,  | 
            |
| 51 | 
                + "壹佰壹拾壹亿壹仟壹佰壹拾壹万壹仟壹佰壹拾壹": 11111111111,  | 
            |
| 52 | 
                + "壹仟壹佰壹拾壹亿壹仟壹佰壹拾壹万壹仟壹佰壹拾壹": 111111111111,  | 
            |
| 53 | 
                + "壹拾壹元整": 11,  | 
            |
| 54 | 
                + "壹佰壹拾壹圆整": 111,  | 
            |
| 55 | 
                + "壹拾壹元正": 11,  | 
            |
| 56 | 
                + "壹拾壹圆正": 11,  | 
            |
| 57 | 
                + "壹拾壹元壹角": 11.1,  | 
            |
| 58 | 
                + "壹拾壹元壹角壹分": 11.11,  | 
            |
| 59 | 
                + "十万": 100000,  | 
            |
| 60 | 
                + "十万零一": 100001,  | 
            |
| 61 | 
                + "一万零一": 10001,  | 
            |
| 62 | 
                + "一万零一十一": 10011,  | 
            |
| 63 | 
                + "一万零一百一十一": 10111,  | 
            |
| 64 | 
                + "一万零百一十一": 10111,  | 
            |
| 65 | 
                + "一十万零一": 100001,  | 
            |
| 66 | 
                + "一百万零一": 1000001,  | 
            |
| 67 | 
                + "一千万零一": 10000001,  | 
            |
| 68 | 
                + "一千零一万一千零一": 10011001,  | 
            |
| 69 | 
                + "一千零一万零一": 10010001,  | 
            |
| 70 | 
                + "一亿零一": 100000001,  | 
            |
| 71 | 
                + "一十亿零一": 1000000001,  | 
            |
| 72 | 
                + "一百亿零一": 10000000001,  | 
            |
| 73 | 
                + "一千零一亿一千零一万一千零一": 100110011001,  | 
            |
| 74 | 
                + "一千亿一千万一千零一": 100010001001,  | 
            |
| 75 | 
                + "一千亿零一": 100000000001,  | 
            |
| 76 | 
                + "零点零零零零零零零零零零零零零零一": 0.000000000000001,  | 
            |
| 77 | 
                + "零点零零零零零零零零零零零零零一": 0.00000000000001,  | 
            |
| 78 | 
                + "零点零零零零零零零零零零零零一": 0.0000000000001,  | 
            |
| 79 | 
                + "零点零零零零零零零零零零零一": 0.000000000001,  | 
            |
| 80 | 
                + "零点零零零零零零零零零零一": 0.00000000001,  | 
            |
| 81 | 
                + "零点零零零零零零零零零一": 0.0000000001,  | 
            |
| 82 | 
                + "零点零零零零零零零零一": 0.000000001,  | 
            |
| 83 | 
                + "零点零零零零零零零一": 0.00000001,  | 
            |
| 84 | 
                + "零点零零零零零零一": 0.0000001,  | 
            |
| 85 | 
                + "零点零零零零零一": 0.000001,  | 
            |
| 86 | 
                + "零点零零零零一": 0.00001,  | 
            |
| 87 | 
                + "零点零零零一": 0.0001,  | 
            |
| 88 | 
                + "零点零零一": 0.001,  | 
            |
| 89 | 
                + "零点零一": 0.01,  | 
            |
| 90 | 
                + "零点一": 0.1,  | 
            |
| 91 | 
                + "负一": -1,  | 
            |
| 92 | 
                + "负二": -2,  | 
            |
| 93 | 
                + "负十": -10,  | 
            |
| 94 | 
                + "负十一": -11,  | 
            |
| 95 | 
                + "负一十一": -11,  | 
            |
| 96 | 
                + # 古语  | 
            |
| 97 | 
                + "廿二": 22,  | 
            |
| 98 | 
                + }  | 
            |
| 99 | 
                +  | 
            |
| 100 | 
                +        self.normal_data_dict = {
               | 
            |
| 101 | 
                + "一一": 11,  | 
            |
| 102 | 
                + "一一一": 111,  | 
            |
| 103 | 
                + "壹壹": 11,  | 
            |
| 104 | 
                + "壹壹壹": 111,  | 
            |
| 105 | 
                + "零点零": 0,  | 
            |
| 106 | 
                + "零点零零": 0,  | 
            |
| 107 | 
                + "一七二零": 1720,  | 
            |
| 108 | 
                + "一七二零点一": 1720.1,  | 
            |
| 109 | 
                + "一七二零点一三四": 1720.134,  | 
            |
| 110 | 
                + "一二三": 123,  | 
            |
| 111 | 
                + "负零点一零": -0.1,  | 
            |
| 112 | 
                + "负一七二零": -1720,  | 
            |
| 113 | 
                + "负一七二零点一": -1720.1,  | 
            |
| 114 | 
                + # 口语  | 
            |
| 115 | 
                + "三万五": 35000,  | 
            |
| 116 | 
                + "十三万五": 135000,  | 
            |
| 117 | 
                + "两千六": 2600,  | 
            |
| 118 | 
                + "一百二": 120,  | 
            |
| 119 | 
                + "一百二十万三": 1203000,  | 
            |
| 120 | 
                + # 繁体  | 
            |
| 121 | 
                + "兩千六": 2600,  | 
            |
| 122 | 
                + # 大写  | 
            |
| 123 | 
                + "壹拾壹元": 11,  | 
            |
| 124 | 
                + "壹佰壹拾壹圆": 111,  | 
            |
| 125 | 
                + "壹拾壹圆": 11,  | 
            |
| 126 | 
                + # 特殊  | 
            |
| 127 | 
                + "〇": 0,  | 
            |
| 128 | 
                + }  | 
            |
| 129 | 
                +  | 
            |
| 130 | 
                +        self.smart_data_dict = {
               | 
            |
| 131 | 
                + "100万": 1000000,  | 
            |
| 132 | 
                + "100万三千": 1003000,  | 
            |
| 133 | 
                + "200亿零四千230": 20000004230,  | 
            |
| 134 | 
                + "一百点123": 100.123,  | 
            |
| 135 | 
                + "10.1万": 101000,  | 
            |
| 136 | 
                + "-10.1万": -101000,  | 
            |
| 137 | 
                + "35.1亿": 3510000000,  | 
            |
| 138 | 
                + "10.1": 10.1,  | 
            |
| 139 | 
                + "-10.1": -10.1,  | 
            |
| 140 | 
                + }  | 
            |
| 141 | 
                +  | 
            |
| 142 | 
                + self.error_smart_datas = [  | 
            |
| 143 | 
                + "10.1万零100",  | 
            |
| 144 | 
                + "10..1万",  | 
            |
| 145 | 
                + ]  | 
            |
| 146 | 
                +  | 
            |
| 147 | 
                + self.error_normal_datas = [  | 
            |
| 148 | 
                + "零点",  | 
            |
| 149 | 
                + "点零",  | 
            |
| 150 | 
                + "零点点",  | 
            |
| 151 | 
                + "零点零大",  | 
            |
| 152 | 
                + ]  | 
            |
| 153 | 
                + self.error_normal_datas.extend(self.error_smart_datas)  | 
            |
| 154 | 
                + self.error_normal_datas.extend(list(self.smart_data_dict.keys()))  | 
            |
| 155 | 
                +  | 
            |
| 156 | 
                + self.error_strict_datas = [  | 
            |
| 157 | 
                + "一一",  | 
            |
| 158 | 
                + "壹壹",  | 
            |
| 159 | 
                + "零点",  | 
            |
| 160 | 
                + "点零",  | 
            |
| 161 | 
                + "点一",  | 
            |
| 162 | 
                + "百十一",  | 
            |
| 163 | 
                + "十一十二",  | 
            |
| 164 | 
                + "负十一十二",  | 
            |
| 165 | 
                + "十七十八",  | 
            |
| 166 | 
                + ]  | 
            |
| 167 | 
                + self.error_strict_datas.extend(self.error_normal_datas)  | 
            |
| 168 | 
                + self.error_strict_datas.extend(list(self.normal_data_dict.keys()))  | 
            |
| 169 | 
                +  | 
            |
| 170 | 
                + # 不可修改位置  | 
            |
| 171 | 
                + self.normal_data_dict.update(self.strict_data_dict)  | 
            |
| 172 | 
                + self.smart_data_dict.update(self.normal_data_dict)  | 
            |
| 173 | 
                +  | 
            |
| 174 | 
                + self.ca = Cn2An()  | 
            |
| 175 | 
                +  | 
            |
| 176 | 
                + def test_cn2an(self) -> None:  | 
            |
| 177 | 
                + for strict_item in self.strict_data_dict.keys():  | 
            |
| 178 | 
                + self.assertEqual(self.ca.cn2an(strict_item, "strict"),  | 
            |
| 179 | 
                + self.strict_data_dict[strict_item])  | 
            |
| 180 | 
                +  | 
            |
| 181 | 
                + for normal_item in self.normal_data_dict.keys():  | 
            |
| 182 | 
                + self.assertEqual(self.ca.cn2an(normal_item, "normal"),  | 
            |
| 183 | 
                + self.normal_data_dict[normal_item])  | 
            |
| 184 | 
                +  | 
            |
| 185 | 
                + for smart_item in self.smart_data_dict.keys():  | 
            |
| 186 | 
                + self.assertEqual(self.ca.cn2an(smart_item, "smart"),  | 
            |
| 187 | 
                + self.smart_data_dict[smart_item])  | 
            |
| 188 | 
                +  | 
            |
| 189 | 
                + for error_strict_item in self.error_strict_datas:  | 
            |
| 190 | 
                + try:  | 
            |
| 191 | 
                + self.ca.cn2an(error_strict_item)  | 
            |
| 192 | 
                + except ValueError as e:  | 
            |
| 193 | 
                + self.assertEqual(type(e), ValueError)  | 
            |
| 194 | 
                + else:  | 
            |
| 195 | 
                +                raise Exception(f'ValueError not raised: {error_strict_item}')
               | 
            |
| 196 | 
                +  | 
            |
| 197 | 
                + for error_normal_item in self.error_normal_datas:  | 
            |
| 198 | 
                + try:  | 
            |
| 199 | 
                + self.ca.cn2an(error_normal_item)  | 
            |
| 200 | 
                + except ValueError as e:  | 
            |
| 201 | 
                + self.assertEqual(type(e), ValueError)  | 
            |
| 202 | 
                + else:  | 
            |
| 203 | 
                +                raise Exception(f'ValueError not raised: {error_normal_item}')
               | 
            |
| 204 | 
                +  | 
            |
| 205 | 
                + for error_smart_item in self.error_smart_datas:  | 
            |
| 206 | 
                + try:  | 
            |
| 207 | 
                + self.ca.cn2an(error_smart_item)  | 
            |
| 208 | 
                + except ValueError as e:  | 
            |
| 209 | 
                + self.assertEqual(type(e), ValueError)  | 
            |
| 210 | 
                + else:  | 
            |
| 211 | 
                +                raise Exception(f'ValueError not raised: {error_smart_item}')
               | 
            |
| 212 | 
                +  | 
            |
| 213 | 
                +  | 
            |
| 214 | 
                +if __name__ == '__main__':  | 
            |
| 215 | 
                + unittest.main()  | 
            
                @@ -0,0 +1,135 @@  | 
            ||
| 1 | 
                +NUMBER_CN2AN = {
               | 
            |
| 2 | 
                + "零": 0,  | 
            |
| 3 | 
                + "〇": 0,  | 
            |
| 4 | 
                + "一": 1,  | 
            |
| 5 | 
                + "壹": 1,  | 
            |
| 6 | 
                + "幺": 1,  | 
            |
| 7 | 
                + "二": 2,  | 
            |
| 8 | 
                + "贰": 2,  | 
            |
| 9 | 
                + "两": 2,  | 
            |
| 10 | 
                + "三": 3,  | 
            |
| 11 | 
                + "叁": 3,  | 
            |
| 12 | 
                + "四": 4,  | 
            |
| 13 | 
                + "肆": 4,  | 
            |
| 14 | 
                + "五": 5,  | 
            |
| 15 | 
                + "伍": 5,  | 
            |
| 16 | 
                + "六": 6,  | 
            |
| 17 | 
                + "陆": 6,  | 
            |
| 18 | 
                + "七": 7,  | 
            |
| 19 | 
                + "柒": 7,  | 
            |
| 20 | 
                + "八": 8,  | 
            |
| 21 | 
                + "捌": 8,  | 
            |
| 22 | 
                + "九": 9,  | 
            |
| 23 | 
                + "玖": 9,  | 
            |
| 24 | 
                +}  | 
            |
| 25 | 
                +UNIT_CN2AN = {
               | 
            |
| 26 | 
                + "十": 10,  | 
            |
| 27 | 
                + "拾": 10,  | 
            |
| 28 | 
                + "百": 100,  | 
            |
| 29 | 
                + "佰": 100,  | 
            |
| 30 | 
                + "千": 1000,  | 
            |
| 31 | 
                + "仟": 1000,  | 
            |
| 32 | 
                + "万": 10000,  | 
            |
| 33 | 
                + "亿": 100000000,  | 
            |
| 34 | 
                +}  | 
            |
| 35 | 
                +UNIT_LOW_AN2CN = {
               | 
            |
| 36 | 
                + 10: "十",  | 
            |
| 37 | 
                + 100: "百",  | 
            |
| 38 | 
                + 1000: "千",  | 
            |
| 39 | 
                + 10000: "万",  | 
            |
| 40 | 
                + 100000000: "亿",  | 
            |
| 41 | 
                +}  | 
            |
| 42 | 
                +NUMBER_LOW_AN2CN = {
               | 
            |
| 43 | 
                + 0: "零",  | 
            |
| 44 | 
                + 1: "一",  | 
            |
| 45 | 
                + 2: "二",  | 
            |
| 46 | 
                + 3: "三",  | 
            |
| 47 | 
                + 4: "四",  | 
            |
| 48 | 
                + 5: "五",  | 
            |
| 49 | 
                + 6: "六",  | 
            |
| 50 | 
                + 7: "七",  | 
            |
| 51 | 
                + 8: "八",  | 
            |
| 52 | 
                + 9: "九",  | 
            |
| 53 | 
                +}  | 
            |
| 54 | 
                +NUMBER_UP_AN2CN = {
               | 
            |
| 55 | 
                + 0: "零",  | 
            |
| 56 | 
                + 1: "壹",  | 
            |
| 57 | 
                + 2: "贰",  | 
            |
| 58 | 
                + 3: "叁",  | 
            |
| 59 | 
                + 4: "肆",  | 
            |
| 60 | 
                + 5: "伍",  | 
            |
| 61 | 
                + 6: "陆",  | 
            |
| 62 | 
                + 7: "柒",  | 
            |
| 63 | 
                + 8: "捌",  | 
            |
| 64 | 
                + 9: "玖",  | 
            |
| 65 | 
                +}  | 
            |
| 66 | 
                +UNIT_LOW_ORDER_AN2CN = [  | 
            |
| 67 | 
                + "",  | 
            |
| 68 | 
                + "十",  | 
            |
| 69 | 
                + "百",  | 
            |
| 70 | 
                + "千",  | 
            |
| 71 | 
                + "万",  | 
            |
| 72 | 
                + "十",  | 
            |
| 73 | 
                + "百",  | 
            |
| 74 | 
                + "千",  | 
            |
| 75 | 
                + "亿",  | 
            |
| 76 | 
                + "十",  | 
            |
| 77 | 
                + "百",  | 
            |
| 78 | 
                + "千",  | 
            |
| 79 | 
                + "万",  | 
            |
| 80 | 
                + "十",  | 
            |
| 81 | 
                + "百",  | 
            |
| 82 | 
                + "千",  | 
            |
| 83 | 
                +]  | 
            |
| 84 | 
                +UNIT_UP_ORDER_AN2CN = [  | 
            |
| 85 | 
                + "",  | 
            |
| 86 | 
                + "拾",  | 
            |
| 87 | 
                + "佰",  | 
            |
| 88 | 
                + "仟",  | 
            |
| 89 | 
                + "万",  | 
            |
| 90 | 
                + "拾",  | 
            |
| 91 | 
                + "佰",  | 
            |
| 92 | 
                + "仟",  | 
            |
| 93 | 
                + "亿",  | 
            |
| 94 | 
                + "拾",  | 
            |
| 95 | 
                + "佰",  | 
            |
| 96 | 
                + "仟",  | 
            |
| 97 | 
                + "万",  | 
            |
| 98 | 
                + "拾",  | 
            |
| 99 | 
                + "佰",  | 
            |
| 100 | 
                + "仟",  | 
            |
| 101 | 
                +]  | 
            |
| 102 | 
                +STRICT_CN_NUMBER = {
               | 
            |
| 103 | 
                + "零": "零",  | 
            |
| 104 | 
                + "一": "一壹",  | 
            |
| 105 | 
                + "二": "二贰",  | 
            |
| 106 | 
                + "三": "三叁",  | 
            |
| 107 | 
                + "四": "四肆",  | 
            |
| 108 | 
                + "五": "五伍",  | 
            |
| 109 | 
                + "六": "六陆",  | 
            |
| 110 | 
                + "七": "七柒",  | 
            |
| 111 | 
                + "八": "八捌",  | 
            |
| 112 | 
                + "九": "九玖",  | 
            |
| 113 | 
                + "十": "十拾",  | 
            |
| 114 | 
                + "百": "百佰",  | 
            |
| 115 | 
                + "千": "千仟",  | 
            |
| 116 | 
                + "万": "万",  | 
            |
| 117 | 
                + "亿": "亿",  | 
            |
| 118 | 
                +}  | 
            |
| 119 | 
                +NORMAL_CN_NUMBER = {
               | 
            |
| 120 | 
                + "零": "零〇",  | 
            |
| 121 | 
                + "一": "一壹幺",  | 
            |
| 122 | 
                + "二": "二贰两",  | 
            |
| 123 | 
                + "三": "三叁仨",  | 
            |
| 124 | 
                + "四": "四肆",  | 
            |
| 125 | 
                + "五": "五伍",  | 
            |
| 126 | 
                + "六": "六陆",  | 
            |
| 127 | 
                + "七": "七柒",  | 
            |
| 128 | 
                + "八": "八捌",  | 
            |
| 129 | 
                + "九": "九玖",  | 
            |
| 130 | 
                + "十": "十拾",  | 
            |
| 131 | 
                + "百": "百佰",  | 
            |
| 132 | 
                + "千": "千仟",  | 
            |
| 133 | 
                + "万": "万",  | 
            |
| 134 | 
                + "亿": "亿",  | 
            |
| 135 | 
                +}  | 
            
                @@ -0,0 +1,29 @@  | 
            ||
| 1 | 
                +import torbjorn as tbn  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from .an2cn import An2Cn  | 
            |
| 4 | 
                +from .cn2an import Cn2An  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +ac = An2Cn()  | 
            |
| 7 | 
                +ca = Cn2An()  | 
            |
| 8 | 
                +  | 
            |
| 9 | 
                +an = 9876543298765432  | 
            |
| 10 | 
                +cn = "九千八百七十六万五千四百三十二亿九千八百七十六万五千四百三十二"  | 
            |
| 11 | 
                +  | 
            |
| 12 | 
                +  | 
            |
| 13 | 
                +@tbn.run_time  | 
            |
| 14 | 
                +def run_cn2an_ten_thousand_times() -> None:  | 
            |
| 15 | 
                + for _ in range(10000):  | 
            |
| 16 | 
                + result = ca.cn2an(cn)  | 
            |
| 17 | 
                + assert result == an  | 
            |
| 18 | 
                +  | 
            |
| 19 | 
                +  | 
            |
| 20 | 
                +@tbn.run_time  | 
            |
| 21 | 
                +def run_an2cn_ten_thousand_times() -> None:  | 
            |
| 22 | 
                + for _ in range(10000):  | 
            |
| 23 | 
                + result = ac.an2cn(an)  | 
            |
| 24 | 
                + assert result == cn  | 
            |
| 25 | 
                +  | 
            |
| 26 | 
                +  | 
            |
| 27 | 
                +if __name__ == '__main__':  | 
            |
| 28 | 
                + run_cn2an_ten_thousand_times()  | 
            |
| 29 | 
                + run_an2cn_ten_thousand_times()  | 
            
                @@ -0,0 +1,104 @@  | 
            ||
| 1 | 
                +import re  | 
            |
| 2 | 
                +from warnings import warn  | 
            |
| 3 | 
                +  | 
            |
| 4 | 
                +from .cn2an import Cn2An  | 
            |
| 5 | 
                +from .an2cn import An2Cn  | 
            |
| 6 | 
                +from .conf import UNIT_CN2AN  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +  | 
            |
| 9 | 
                +class Transform(object):  | 
            |
| 10 | 
                + def __init__(self) -> None:  | 
            |
| 11 | 
                + self.all_num = "零一二三四五六七八九"  | 
            |
| 12 | 
                + self.all_unit = "".join(list(UNIT_CN2AN.keys()))  | 
            |
| 13 | 
                + self.cn2an = Cn2An().cn2an  | 
            |
| 14 | 
                + self.an2cn = An2Cn().an2cn  | 
            |
| 15 | 
                +        self.cn_pattern = f"负?([{self.all_num}{self.all_unit}]+点)?[{self.all_num}{self.all_unit}]+"
               | 
            |
| 16 | 
                +        self.smart_cn_pattern = f"-?([0-9]+.)?[0-9]+[{self.all_unit}]+"
               | 
            |
| 17 | 
                +  | 
            |
| 18 | 
                + def transform(self, inputs: str, method: str = "cn2an") -> str:  | 
            |
| 19 | 
                + if method == "cn2an":  | 
            |
| 20 | 
                +            inputs = inputs.replace("廿", "二十").replace("半", "0.5").replace("两", "2")
               | 
            |
| 21 | 
                + # date  | 
            |
| 22 | 
                + inputs = re.sub(  | 
            |
| 23 | 
                +                fr"((({self.smart_cn_pattern})|({self.cn_pattern}))年)?([{self.all_num}十]+月)?([{self.all_num}十]+日)?",
               | 
            |
| 24 | 
                + lambda x: self.__sub_util(x.group(), "cn2an", "date"), inputs)  | 
            |
| 25 | 
                + # fraction  | 
            |
| 26 | 
                +            inputs = re.sub(fr"{self.cn_pattern}分之{self.cn_pattern}",
               | 
            |
| 27 | 
                + lambda x: self.__sub_util(x.group(), "cn2an", "fraction"), inputs)  | 
            |
| 28 | 
                + # percent  | 
            |
| 29 | 
                +            inputs = re.sub(fr"百分之{self.cn_pattern}",
               | 
            |
| 30 | 
                + lambda x: self.__sub_util(x.group(), "cn2an", "percent"), inputs)  | 
            |
| 31 | 
                + # celsius  | 
            |
| 32 | 
                +            inputs = re.sub(fr"{self.cn_pattern}摄氏度",
               | 
            |
| 33 | 
                + lambda x: self.__sub_util(x.group(), "cn2an", "celsius"), inputs)  | 
            |
| 34 | 
                + # number  | 
            |
| 35 | 
                + output = re.sub(self.cn_pattern,  | 
            |
| 36 | 
                + lambda x: self.__sub_util(x.group(), "cn2an", "number"), inputs)  | 
            |
| 37 | 
                +  | 
            |
| 38 | 
                + elif method == "an2cn":  | 
            |
| 39 | 
                + # date  | 
            |
| 40 | 
                +            inputs = re.sub(r"(\d{2,4}年)?(\d{1,2}月)?(\d{1,2}日)?",
               | 
            |
| 41 | 
                + lambda x: self.__sub_util(x.group(), "an2cn", "date"), inputs)  | 
            |
| 42 | 
                + # fraction  | 
            |
| 43 | 
                + inputs = re.sub(r"\d+/\d+",  | 
            |
| 44 | 
                + lambda x: self.__sub_util(x.group(), "an2cn", "fraction"), inputs)  | 
            |
| 45 | 
                + # percent  | 
            |
| 46 | 
                + inputs = re.sub(r"-?(\d+\.)?\d+%",  | 
            |
| 47 | 
                + lambda x: self.__sub_util(x.group(), "an2cn", "percent"), inputs)  | 
            |
| 48 | 
                + # celsius  | 
            |
| 49 | 
                + inputs = re.sub(r"\d+℃",  | 
            |
| 50 | 
                + lambda x: self.__sub_util(x.group(), "an2cn", "celsius"), inputs)  | 
            |
| 51 | 
                + # number  | 
            |
| 52 | 
                + output = re.sub(r"-?(\d+\.)?\d+",  | 
            |
| 53 | 
                + lambda x: self.__sub_util(x.group(), "an2cn", "number"), inputs)  | 
            |
| 54 | 
                + else:  | 
            |
| 55 | 
                +            raise ValueError(f"error method: {method}, only support 'cn2an' and 'an2cn'!")
               | 
            |
| 56 | 
                +  | 
            |
| 57 | 
                + return output  | 
            |
| 58 | 
                +  | 
            |
| 59 | 
                + def __sub_util(self, inputs, method: str = "cn2an", sub_mode: str = "number") -> str:  | 
            |
| 60 | 
                + try:  | 
            |
| 61 | 
                + if inputs:  | 
            |
| 62 | 
                + if method == "cn2an":  | 
            |
| 63 | 
                + if sub_mode == "date":  | 
            |
| 64 | 
                +                        return re.sub(fr"(({self.smart_cn_pattern})|({self.cn_pattern}))",
               | 
            |
| 65 | 
                + lambda x: str(self.cn2an(x.group(), "smart")), inputs)  | 
            |
| 66 | 
                + elif sub_mode == "fraction":  | 
            |
| 67 | 
                + if inputs[0] != "百":  | 
            |
| 68 | 
                + frac_result = re.sub(self.cn_pattern,  | 
            |
| 69 | 
                + lambda x: str(self.cn2an(x.group(), "smart")), inputs)  | 
            |
| 70 | 
                +                            numerator, denominator = frac_result.split("分之")
               | 
            |
| 71 | 
                +                            return f"{denominator}/{numerator}"
               | 
            |
| 72 | 
                + else:  | 
            |
| 73 | 
                + return inputs  | 
            |
| 74 | 
                + elif sub_mode == "percent":  | 
            |
| 75 | 
                +                        return re.sub(f"(?<=百分之){self.cn_pattern}",
               | 
            |
| 76 | 
                +                                      lambda x: str(self.cn2an(x.group(), "smart")), inputs).replace("百分之", "") + "%"
               | 
            |
| 77 | 
                + elif sub_mode == "celsius":  | 
            |
| 78 | 
                +                        return re.sub(f"{self.cn_pattern}(?=摄氏度)",
               | 
            |
| 79 | 
                +                                      lambda x: str(self.cn2an(x.group(), "smart")), inputs).replace("摄氏度", "℃")
               | 
            |
| 80 | 
                + elif sub_mode == "number":  | 
            |
| 81 | 
                + return str(self.cn2an(inputs, "smart"))  | 
            |
| 82 | 
                + else:  | 
            |
| 83 | 
                +                        raise Exception(f"error sub_mode: {sub_mode} !")
               | 
            |
| 84 | 
                + else:  | 
            |
| 85 | 
                + if sub_mode == "date":  | 
            |
| 86 | 
                + inputs = re.sub(r"\d+(?=年)",  | 
            |
| 87 | 
                + lambda x: self.an2cn(x.group(), "direct"), inputs)  | 
            |
| 88 | 
                + return re.sub(r"\d+",  | 
            |
| 89 | 
                + lambda x: self.an2cn(x.group(), "low"), inputs)  | 
            |
| 90 | 
                + elif sub_mode == "fraction":  | 
            |
| 91 | 
                + frac_result = re.sub(r"\d+", lambda x: self.an2cn(x.group(), "low"), inputs)  | 
            |
| 92 | 
                +                        numerator, denominator = frac_result.split("/")
               | 
            |
| 93 | 
                +                        return f"{denominator}分之{numerator}"
               | 
            |
| 94 | 
                + elif sub_mode == "celsius":  | 
            |
| 95 | 
                + return self.an2cn(inputs[:-1], "low") + "摄氏度"  | 
            |
| 96 | 
                + elif sub_mode == "percent":  | 
            |
| 97 | 
                + return "百分之" + self.an2cn(inputs[:-1], "low")  | 
            |
| 98 | 
                + elif sub_mode == "number":  | 
            |
| 99 | 
                + return self.an2cn(inputs, "low")  | 
            |
| 100 | 
                + else:  | 
            |
| 101 | 
                +                        raise Exception(f"error sub_mode: {sub_mode} !")
               | 
            |
| 102 | 
                + except Exception as e:  | 
            |
| 103 | 
                + warn(str(e))  | 
            |
| 104 | 
                + return inputs  | 
            
                @@ -0,0 +1,40 @@  | 
            ||
| 1 | 
                +import unittest  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from .transform import Transform  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +class TransformTest(unittest.TestCase):  | 
            |
| 7 | 
                + def setUp(self) -> None:  | 
            |
| 8 | 
                +        self.strict_data_dict = {
               | 
            |
| 9 | 
                + "小王捡了100块钱": "小王捡了一百块钱",  | 
            |
| 10 | 
                + "用户增长最快的3个城市": "用户增长最快的三个城市",  | 
            |
| 11 | 
                + "小王的生日是2001年3月4日": "小王的生日是二零零一年三月四日",  | 
            |
| 12 | 
                + "小王的生日是2012年12月12日": "小王的生日是二零一二年十二月十二日",  | 
            |
| 13 | 
                + "今天股价上涨了8%": "今天股价上涨了百分之八",  | 
            |
| 14 | 
                + "第2天股价下降了-3.8%": "第二天股价下降了百分之负三点八",  | 
            |
| 15 | 
                + "抛出去的硬币为正面的概率是1/2": "抛出去的硬币为正面的概率是二分之一",  | 
            |
| 16 | 
                + "现在室内温度为39℃,很热啊!": "现在室内温度为三十九摄氏度,很热啊!",  | 
            |
| 17 | 
                + "创业板指9月9日早盘低开1.57%": "创业板指九月九日早盘低开百分之一点五七"  | 
            |
| 18 | 
                + }  | 
            |
| 19 | 
                +  | 
            |
| 20 | 
                +        self.smart_data_dict = {
               | 
            |
| 21 | 
                + "约2.5亿年~6500万年": "约250000000年~65000000年",  | 
            |
| 22 | 
                + "廿二日,日出东方": "22日,日出东方",  | 
            |
| 23 | 
                + "大陆": "大陆",  | 
            |
| 24 | 
                + "半斤": "0.5斤",  | 
            |
| 25 | 
                + "两个": "2个",  | 
            |
| 26 | 
                + }  | 
            |
| 27 | 
                +  | 
            |
| 28 | 
                + self.t = Transform()  | 
            |
| 29 | 
                +  | 
            |
| 30 | 
                + def test_transform(self) -> None:  | 
            |
| 31 | 
                + for strict_item in self.strict_data_dict.keys():  | 
            |
| 32 | 
                + self.assertEqual(self.t.transform(strict_item, "an2cn"), self.strict_data_dict[strict_item])  | 
            |
| 33 | 
                + self.assertEqual(self.t.transform(self.strict_data_dict[strict_item], "cn2an"), strict_item)  | 
            |
| 34 | 
                +  | 
            |
| 35 | 
                + for smart_item in self.smart_data_dict.keys():  | 
            |
| 36 | 
                + self.assertEqual(self.t.transform(smart_item, "cn2an"), self.smart_data_dict[smart_item])  | 
            |
| 37 | 
                +  | 
            |
| 38 | 
                +  | 
            |
| 39 | 
                +if __name__ == '__main__':  | 
            |
| 40 | 
                + unittest.main()  |