namkuner's picture
Upload folder using huggingface_hub
ddd337d verified
from singleton_decorator import singleton
import re
from .Decimal import Decimal
from .Fraction import Fraction
@singleton
class Measure:
def __init__(self):
super().__init__()
# Regex để phát hiện phân số
self.fraction_regex = re.compile(
r"(((?:-?\d* )?-?\d+ *\/ *-? *\d+)|(-?\d* *(?:½|⅓|⅔|¼|¾|⅕|⅖|⅗|⅘|⅙|⅚|⅐|⅛|⅜|⅝|⅞|⅑|⅒)))")
# Regex để phát hiện xem có nên sử dụng "của một" hay không
self.of_a_regex = re.compile(r"(-?\d+ -?\d+ *\/ *-? *\d+)|(-?\d+ *(?:½|⅓|⅔|¼|¾|⅕|⅖|⅗|⅘|⅙|⅚|⅐|⅛|⅜|⅝|⅞|⅑|⅒))")
# Regex để phát hiện đầu vào để chuyển đổi số, bao gồm cả hậu tố triệu/tỷ tiềm năng
self.value_regex = re.compile(r"(-?(?: |\d)*\.?\d+ *(?:nghìn|triệu|tỷ|nghìn tỷ|triệu tỷ|tỷ tỷ)?)")
# Regex để lọc bỏ dấu phẩy
self.filter_regex = re.compile(r"[,]")
# Regex để lọc bỏ khoảng trắng
self.filter_space_regex = re.compile(r"[ ]")
# Regex để lọc bỏ chữ cái
self.letter_filter_regex = re.compile(r"[^0-9\-\.]")
# Từ điển tiền tố cho 10^i với i > 0
self.prefix_dict = {
"Y": "yotta",
"Z": "zetta",
"E": "exa",
"P": "peta",
"T": "tera",
"G": "giga",
"M": "mega",
"k": "kilo",
"h": "hecto",
"da": "deca",
"d": "deci",
"c": "centi",
"m": "milli",
"μ": "micro",
"µ": "micro",
"n": "nano",
"p": "pico",
"f": "femto",
"a": "atto",
"z": "zepto",
"y": "yocto"
}
# Từ điển dịch cho các loại đơn vị có thể thêm tiền tố
self.prefixable_trans_dict = {
"m": {
"singular": "mét",
"plural": "mét"
},
"b": {
"singular": "bit",
"plural": "bit"
},
"B": {
"singular": "byte",
"plural": "byte"
},
"bps": {
"singular": "bit trên giây",
"plural": "bit trên giây"
},
"Bps": {
"singular": "byte trên giây",
"plural": "byte trên giây"
},
"g": {
"singular": "gram",
"plural": "gram"
},
"gf": {
"singular": "gram lực",
"plural": "gram lực"
},
"W": {
"singular": "oát",
"plural": "oát"
},
"Wh": {
"singular": "oát giờ",
"plural": "oát giờ"
},
"Hz": {
"singular": "héc",
"plural": "héc"
},
"J": {
"singular": "jun",
"plural": "jun"
},
"L": {
"singular": "lít",
"plural": "lít"
},
"V": {
"singular": "vôn",
"plural": "vôn"
},
"f": {
"singular": "fara",
"plural": "fara"
},
"s": {
"singular": "giây",
"plural": "giây"
},
"A": {
"singular": "ampe",
"plural": "ampe"
},
"Ah": {
"singular": "ampe giờ",
"plural": "ampe giờ"
},
"Pa": {
"singular": "pascal",
"plural": "pascal"
},
"C": {
"singular": "culông",
"plural": "culông"
},
"Bq": {
"singular": "becquerel",
"plural": "becquerel"
},
"N": {
"singular": "niutơn",
"plural": "niutơn"
},
"bar": {
"singular": "bar",
"plural": "bar"
},
"lm": {
"singular": "lumen",
"plural": "lumen"
},
"cal": {
"singular": "calo",
"plural": "calo"
},
}
# Từ điển đã được biến đổi sử dụng self.prefixable_trans_dict và từ điển tiền tố
self.prefixed_dict = {
prefix + prefixed: {"singular": self.prefix_dict[prefix] + self.prefixable_trans_dict[prefixed]["singular"],
"plural": self.prefix_dict[prefix] + self.prefixable_trans_dict[prefixed]["plural"]} for
prefixed in self.prefixable_trans_dict for prefix in self.prefix_dict}
self.prefixed_dict = {**self.prefixed_dict, **self.prefixable_trans_dict}
# Từ điển dịch cho các loại đơn vị không có tiền tố
self.custom_dict = {
"%": {
"singular": "phần trăm",
"plural": "phần trăm"
},
"pc": {
"singular": "phần trăm",
"plural": "phần trăm"
},
"ft": {
"singular": "foot",
"plural": "foot"
},
"mi": {
"singular": "dặm",
"plural": "dặm"
},
"mb": {
"singular": "megabyte",
"plural": "megabyte"
},
"ha": {
"singular": "hecta",
"plural": "hecta"
},
"\"": {
"singular": "inch",
"plural": "inch"
},
"in": {
"singular": "inch",
"plural": "inch"
},
"\'": {
"singular": "foot",
"plural": "foot"
},
"rpm": {
"singular": "vòng trên phút",
"plural": "vòng trên phút"
},
"hp": {
"singular": "mã lực",
"plural": "mã lực"
},
"cc": {
"singular": "xăng-ti-mét khối",
"plural": "xăng-ti-mét khối"
},
"oz": {
"singular": "aoxơ",
"plural": "aoxơ",
},
"mph": {
"singular": "dặm trên giờ",
"plural": "dặm trên giờ"
},
"lb": {
"singular": "pao",
"plural": "pao"
},
"lbs": {
"singular": "pao",
"plural": "pao"
},
"kt": {
"singular": "nút",
"plural": "nút"
},
"dB": {
"singular": "đề-xi-ben",
"plural": "đề-xi-ben"
},
"AU": {
"singular": "đơn vị thiên văn",
"plural": "đơn vị thiên văn"
},
"st": {
"singular": "stone",
"plural": "stone"
},
"yd": {
"singular": "yard",
"plural": "yard"
},
"yr": {
"singular": "năm",
"plural": "năm"
},
"yrs": {
"singular": "năm",
"plural": "năm"
},
"eV": {
"singular": "electron vôn",
"plural": "electron vôn"
},
"/": {
"singular": "trên",
"plural": "trên"
},
"sq": {
"singular": "vuông",
"plural": "vuông"
},
"2": {
"singular": "vuông",
"plural": "vuông"
},
"²": {
"singular": "vuông",
"plural": "vuông"
},
"3": {
"singular": "khối",
"plural": "khối"
},
"³": {
"singular": "khối",
"plural": "khối"
},
"h": {
"singular": "giờ",
"plural": "giờ"
},
"hr": {
"singular": "giờ",
"plural": "giờ"
},
"hrs": {
"singular": "giờ",
"plural": "giờ"
},
"ch": {
"singular": "chain",
"plural": "chain"
},
"KiB": {
"singular": "kibibyte",
"plural": "kibibyte"
},
"MiB": {
"singular": "mebibyte",
"plural": "mebibyte"
},
"GiB": {
"singular": "gibibyte",
"plural": "gibibyte"
},
"pH": {
"singular": "pH",
"plural": "pH"
},
"kph": {
"singular": "kilômét trên giờ",
"plural": "kilômét trên giờ"
},
"Da": {
"singular": "đalton",
"plural": "đalton"
},
"cwt": {
"singular": "hundredweight",
"plural": "hundredweight"
},
"Sv": {
"singular": "sievert",
"plural": "sievert",
},
"C": {
"singular": "độ xen-xi-út",
"plural": "độ xen-xi-út"
},
"degrees": {
"singular": "độ",
"plural": "độ"
},
"degree": {
"singular": "độ",
"plural": "độ"
},
"atm": {
"singular": "át-mốt-phê",
"plural": "át-mốt-phê"
},
"min": {
"singular": "phút",
"plural": "phút"
},
"cd": {
"singular": "can-đê-la",
"plural": "can-đê-la"
},
"ly": {
"singular": "năm ánh sáng",
"plural": "năm ánh sáng"
},
"kts": {
"singular": "nút",
"plural": "nút"
},
"mol": {
"singular": "mol",
"plural": "mol"
},
"Nm": {
"singular": "niutơn mét",
"plural": "niutơn mét"
},
"Ω": {
"singular": "ôm",
"plural": "ôm"
},
"bbl": {
"singular": "thùng",
"plural": "thùng"
},
"gal": {
"singular": "gallon",
"plural": "gallon"
},
"cal": {
"singular": "cỡ nòng",
"plural": "cỡ nòng"
}
}
# Ghi đè và thêm giá trị từ custom_dict vào prefixed_dict
self.prefixed_dict = {**self.prefixed_dict, **self.custom_dict}
# Phiên bản viết thường của self.prefixed_dict
self.lower_prefixed_dict = {key.lower(): self.prefixed_dict[key] for key in self.prefixed_dict}
# Hậu tố đặc biệt mà tổng hậu tố nên được tách ra
self.special_suffixes = re.compile(r"(\/|trên(?!trăm)|vuông|2|²|3|³)")
# Chuyển đổi Decimal và Fraction
self.decimal = Decimal()
self.fraction = Fraction()
def convert(self, token: str) -> str:
# 1 Lọc bỏ dấu phẩy
token = self.filter_regex.sub("", token)
result_list = []
# Số nhiều mặc định là false, vì "/s" nên là "trên giây"
plural = False
# 2 Thử khớp với một phân số
match = self.fraction_regex.match(token)
if match:
# 2.1 Nếu tồn tại, chuyển đổi thành văn bản sử dụng bộ chuyển đổi Fraction
result_list.append(self.fraction.convert(match.group(0)))
# Chuyển token thành phần còn lại. Vì sử dụng match thay vì search,
# phần đầu của dòng tiếp theo có thể không cần thiết
token = token[:match.span()[0]] + token[match.span()[1]:]
# Lọc bỏ khoảng trắng
token = self.filter_space_regex.sub("", token)
# Nếu có một số trước phân số, ví dụ "8 1/2" hoặc "8 ½", thì chúng ta thêm "của một", và giữ nguyên số ít
# Ngược lại, chúng ta chuyển sang số nhiều
if self.of_a_regex.match(match.group(0)):
plural = True
else:
result_list.append("của một")
else:
# 3 Thử khớp với "x,y" hoặc "x"
match = self.value_regex.match(token)
if match:
# 3.1 Chuyển không có khoảng trắng cho bộ chuyển đổi decimal
result_list.append(self.decimal.convert(self.filter_space_regex.sub("", match.group(1))))
token = token[:match.span()[0]] + token[match.span()[1]:]
# Số nhiều là False khi giá trị tuyệt đối của số thập phân là 1, và giá trị thập phân không có dạng "1,x"
# Ngược lại là True
if abs(float(self.letter_filter_regex.sub("", match.group(1)))) != 1 or "," in match.group(1):
plural = True
# Biến chỉ ra liệu từ "trên" vừa được sử dụng
# Điều này được sử dụng để phát hiện số nhiều
per = False
# 4 Lặp qua phần còn lại của token
for split_token in token.split(" "):
for i, token in enumerate(self.split_token(split_token)):
# Thêm tên thích hợp của hậu tố nếu tồn tại
# Thử không phân biệt chữ hoa chữ thường nếu lần trước thất bại
if token in self.prefixed_dict:
result_list.append(self.prefixed_dict[token]["plural" if plural and not per else "singular"])
elif token.lower() in self.lower_prefixed_dict:
result_list.append(
self.lower_prefixed_dict[token.lower()]["plural" if plural and not per else "singular"])
else:
result_list.append(token)
# Nếu kết quả trước đó là "trên", đặt per thành True để sử dụng "singular" cho từ tiếp theo.
# Nhưng chỉ khi "trên" không phải là hậu tố đầu tiên. Ví dụ: "5/km2" là "năm trên kilômét vuông"
if result_list[-1] == "trên" and i != 0:
per = True
# Nếu từ cuối cùng không phải là "trên", và không phải "vuông" hoặc "khối", đặt lại per thành False.
# Nếu "trên" được sử dụng, tiếp theo là "vuông" hoặc "khối", chúng ta muốn giữ "singular" cho
# từ sắp tới
elif result_list[-1] not in ("vuông", "khối"):
per = False
result = " ".join(result_list)
# 5 Xử lý trường hợp đặc biệt: xentimét khối -> xăng-ti-mét khối
result = re.sub(r"xentimét khối", "xăng-ti-mét khối", result)
return result