|
from typing import List
|
|
|
|
from singleton_decorator import singleton
|
|
import re
|
|
from .Roman import RomanVietnamese
|
|
|
|
|
|
@singleton
|
|
class CardinalVietnamese:
|
|
"""
|
|
Các bước:
|
|
- 1 Loại bỏ dấu chấm
|
|
- 2 Kiểm tra xem có phải là số La Mã không
|
|
- 3 Nếu đúng, chuyển đổi số La Mã lớn nhất tìm thấy thành số nguyên, sau đó thành chuỗi đại diện cho số nguyên đó
|
|
- 4 Nếu đúng, kiểm tra xem có nên thêm hậu tố "'s" không (xem trường hợp đặc biệt)
|
|
- 5 Lọc bỏ các ký tự không phải số, trừ "-"
|
|
- 6 Kiểm tra xem có nên sử dụng tiền tố "âm" không
|
|
- 7 Loại bỏ tất cả các ký tự "-" còn lại
|
|
- 8 Nếu là "0", thêm "không" vào danh sách đầu ra
|
|
- 9 Nếu không phải "0", chia chuỗi thành các phần tối đa 3 chữ số, sao cho phần nhỏ nhất bao gồm các ký tự ngoài cùng bên trái
|
|
- 10 Chia mỗi phần thành `trăm` và `phần còn lại`
|
|
- 11 Thêm "x trăm" nếu `trăm` > 0
|
|
- 12 Thêm giá trị văn bản đại diện cho `phần còn lại`
|
|
- 13 Thêm hậu tố cho phần, ví dụ: triệu, tỷ, v.v.
|
|
- 14 Thêm đầu ra cho phần vào tổng đầu ra
|
|
- 15 Kết hợp danh sách đầu ra tổng thành một chuỗi
|
|
- 16 Thêm tiền tố và/hoặc hậu tố
|
|
|
|
Trường hợp đặc biệt:
|
|
II -> hai
|
|
-2 -> âm hai
|
|
I. -> một
|
|
IV's -> bốn's
|
|
|
|
Ghi chú:
|
|
- Không có "và" hoặc dấu gạch ngang trong kết quả, ví dụ: không có "hai mươi mốt" hoặc "một trăm lẻ một"
|
|
"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.filter_regex = re.compile("[^0-9\-]")
|
|
self.filter_strict_regex = re.compile("[^0-9]")
|
|
self.dot_filter_regex = re.compile("[.]")
|
|
|
|
self.scale_suffixes = [
|
|
"nghìn",
|
|
"triệu",
|
|
"tỷ",
|
|
"nghìn tỷ",
|
|
"triệu tỷ",
|
|
"tỷ tỷ"
|
|
]
|
|
|
|
self.small_trans_dict = {
|
|
"1": "một",
|
|
"2": "hai",
|
|
"3": "ba",
|
|
"4": "bốn",
|
|
"5": "năm",
|
|
"6": "sáu",
|
|
"7": "bảy",
|
|
"8": "tám",
|
|
"9": "chín",
|
|
}
|
|
|
|
self.tens_trans_dict = {
|
|
"1": "mười",
|
|
"2": "hai mươi",
|
|
"3": "ba mươi",
|
|
"4": "bốn mươi",
|
|
"5": "năm mươi",
|
|
"6": "sáu mươi",
|
|
"7": "bảy mươi",
|
|
"8": "tám mươi",
|
|
"9": "chín mươi",
|
|
}
|
|
|
|
self.special_trans_dict = {
|
|
11: "mười một",
|
|
12: "mười hai",
|
|
13: "mười ba",
|
|
14: "mười bốn",
|
|
15: "mười lăm",
|
|
16: "mười sáu",
|
|
17: "mười bảy",
|
|
18: "mười tám",
|
|
19: "mười chín"
|
|
}
|
|
|
|
self.roman = RomanVietnamese()
|
|
|
|
def _give_chunk(self, num_str: str, size: int = 3) -> str:
|
|
while num_str:
|
|
yield num_str[-size:]
|
|
num_str = num_str[:-size]
|
|
|
|
def convert(self, token: str) -> str:
|
|
token = self.dot_filter_regex.sub("", token)
|
|
|
|
suffix = ""
|
|
if self.roman.check_if_roman(token):
|
|
token, suffix = self.roman.convert(token)
|
|
|
|
token = self.filter_regex.sub("", token)
|
|
|
|
prefix = ""
|
|
while len(token) > 0 and token[0] == "-":
|
|
token = token[1:]
|
|
prefix = "âm" if prefix == "" else ""
|
|
|
|
token = self.filter_strict_regex.sub("", token)
|
|
|
|
if token == len(token) * "0":
|
|
return "không"
|
|
|
|
chunks = list(self._give_chunk(token))
|
|
text_list = []
|
|
|
|
for depth, chunk in enumerate(chunks):
|
|
chunk_text = self._convert_chunk(chunk, depth == len(chunks) - 1)
|
|
if chunk_text:
|
|
if depth > 0:
|
|
chunk_text.append(self.scale_suffixes[depth - 1])
|
|
text_list = chunk_text + text_list
|
|
|
|
result = " ".join(text_list)
|
|
|
|
if prefix:
|
|
result = f"{prefix} {result}"
|
|
if suffix:
|
|
result = f"{result}{suffix}"
|
|
|
|
return result
|
|
|
|
def _convert_chunk(self, chunk: str, is_last_chunk: bool) -> List[str]:
|
|
chunk_text = []
|
|
length = len(chunk)
|
|
|
|
|
|
if length == 3:
|
|
if chunk[0] != '0':
|
|
chunk_text.append(self.small_trans_dict[chunk[0]])
|
|
chunk_text.append("trăm")
|
|
elif not is_last_chunk and (chunk[1] != '0' or chunk[2] != '0'):
|
|
chunk_text.append("không trăm")
|
|
|
|
|
|
if length >= 2:
|
|
if chunk[-2:] in self.special_trans_dict:
|
|
chunk_text.append(self.special_trans_dict[chunk[-2:]])
|
|
else:
|
|
if chunk[-2] != '0':
|
|
chunk_text.append(self.tens_trans_dict[chunk[-2]])
|
|
if chunk[-1] != '0':
|
|
if chunk[-1] == '1' and chunk[-2] != '1':
|
|
chunk_text.append("mốt")
|
|
else:
|
|
chunk_text.append(self.small_trans_dict[chunk[-1]])
|
|
elif chunk[-1] != '0':
|
|
if len(chunk_text) > 0 or not is_last_chunk:
|
|
chunk_text.append("lẻ")
|
|
chunk_text.append(self.small_trans_dict[chunk[-1]])
|
|
elif length == 1 and chunk != '0':
|
|
chunk_text.append(self.small_trans_dict[chunk])
|
|
|
|
return chunk_text
|
|
|
|
if __name__ == "__main__":
|
|
cardinal_converter = CardinalVietnamese()
|
|
|
|
|
|
example1 = "20211231"
|
|
result1 = cardinal_converter.convert(example1)
|
|
print(f"Số: {example1}")
|
|
print(f"Chuyển đổi: {result1}")
|
|
print()
|
|
|
|
|
|
example2 = "-5678213"
|
|
result2 = cardinal_converter.convert(example2)
|
|
print(f"Số: {example2}")
|
|
print(f"Chuyển đổi: {result2}")
|
|
print()
|
|
|
|
|
|
example3 = "1000000"
|
|
result3 = cardinal_converter.convert(example3)
|
|
print(f"Số: {example3}")
|
|
print(f"Chuyển đổi: {result3}") |