|
|
from typing import Union |
|
|
|
|
|
from proces import preprocess |
|
|
|
|
|
from .conf import NUMBER_LOW_AN2CN, NUMBER_UP_AN2CN, UNIT_LOW_ORDER_AN2CN, UNIT_UP_ORDER_AN2CN |
|
|
|
|
|
|
|
|
class An2Cn(object): |
|
|
def __init__(self) -> None: |
|
|
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: Union[str, int, float] = None, mode: str = "low") -> str: |
|
|
"""阿拉伯数字转中文数字 |
|
|
|
|
|
: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(f"mode 仅支持 {str(self.mode_list)} !") |
|
|
|
|
|
|
|
|
|
|
|
if not isinstance(inputs, str): |
|
|
inputs = self.__number_to_string(inputs) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inputs = preprocess(inputs, pipelines=[ |
|
|
"traditional_to_simplified", |
|
|
"full_angle_to_half_angle" |
|
|
]) |
|
|
|
|
|
|
|
|
self.__check_inputs_is_valid(inputs) |
|
|
|
|
|
|
|
|
if inputs[0] == "-": |
|
|
sign = "负" |
|
|
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") + "元整" |
|
|
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 + "元整" |
|
|
elif len_dec_data == 1: |
|
|
raise ValueError(f"异常输出:{dec_data}") |
|
|
elif len_dec_data == 2: |
|
|
if dec_data[1] != "零": |
|
|
if int_data == "零": |
|
|
output = dec_data[1] + "角" |
|
|
else: |
|
|
output = int_data + "元" + dec_data[1] + "角" |
|
|
else: |
|
|
output = int_data + "元整" |
|
|
else: |
|
|
if dec_data[1] != "零": |
|
|
if dec_data[2] != "零": |
|
|
if int_data == "零": |
|
|
output = dec_data[1] + "角" + dec_data[2] + "分" |
|
|
else: |
|
|
output = int_data + "元" + dec_data[1] + "角" + dec_data[2] + "分" |
|
|
else: |
|
|
if int_data == "零": |
|
|
output = dec_data[1] + "角" |
|
|
else: |
|
|
output = int_data + "元" + dec_data[1] + "角" |
|
|
else: |
|
|
if dec_data[2] != "零": |
|
|
if int_data == "零": |
|
|
output = dec_data[2] + "分" |
|
|
else: |
|
|
output = int_data + "元" + "零" + dec_data[2] + "分" |
|
|
else: |
|
|
output = int_data + "元整" |
|
|
else: |
|
|
output = self.__integer_convert(integer_data, mode) + self.__decimal_convert(decimal_data, mode) |
|
|
else: |
|
|
raise ValueError(f"输入格式错误:{inputs}!") |
|
|
else: |
|
|
raise ValueError("输入数据为空!") |
|
|
|
|
|
return sign + output |
|
|
|
|
|
def __direct_convert(self, inputs: str) -> str: |
|
|
_output = "" |
|
|
for d in inputs: |
|
|
if d == ".": |
|
|
_output += "点" |
|
|
else: |
|
|
_output += self.number_low[int(d)] |
|
|
return _output |
|
|
|
|
|
@staticmethod |
|
|
def __number_to_string(number_data: Union[int, float]) -> str: |
|
|
|
|
|
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: str) -> None: |
|
|
|
|
|
all_check_keys = self.all_num + ".-" |
|
|
for data in check_data: |
|
|
if data not in all_check_keys: |
|
|
raise ValueError(f"输入的数据不在转化范围内:{data}!") |
|
|
|
|
|
def __integer_convert(self, integer_data: str, mode: str) -> str: |
|
|
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(f"error mode: {mode}") |
|
|
|
|
|
|
|
|
integer_data = str(int(integer_data)) |
|
|
|
|
|
len_integer_data = len(integer_data) |
|
|
if len_integer_data > len(unit_list): |
|
|
raise ValueError(f"超出数据范围,最长支持 {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] == "零": |
|
|
output_an += numeral_list[int(d)] |
|
|
|
|
|
output_an = output_an.replace("零零", "零").replace("零万", "万").replace("零亿", "亿").replace("亿万", "亿") \ |
|
|
.strip("零") |
|
|
|
|
|
|
|
|
if output_an[:2] in ["一十"]: |
|
|
output_an = output_an[1:] |
|
|
|
|
|
|
|
|
if not output_an: |
|
|
output_an = "零" |
|
|
|
|
|
return output_an |
|
|
|
|
|
def __decimal_convert(self, decimal_data: str, o_mode: str) -> str: |
|
|
len_decimal_data = len(decimal_data) |
|
|
|
|
|
if len_decimal_data > 16: |
|
|
print(f"注意:小数部分长度为 {len_decimal_data} ,将自动截取前 16 位有效精度!") |
|
|
decimal_data = decimal_data[:16] |
|
|
|
|
|
if len_decimal_data: |
|
|
output_an = "点" |
|
|
else: |
|
|
output_an = "" |
|
|
|
|
|
if o_mode == "low": |
|
|
numeral_list = NUMBER_LOW_AN2CN |
|
|
elif o_mode == "up": |
|
|
numeral_list = NUMBER_UP_AN2CN |
|
|
else: |
|
|
raise ValueError(f"error mode: {o_mode}") |
|
|
|
|
|
for data in decimal_data: |
|
|
output_an += numeral_list[int(data)] |
|
|
return output_an |
|
|
|