import re from difflib import SequenceMatcher from . import Common_MyUtils as MyUtils ex = MyUtils.exc # =============================== # 1. Abbreviation # =============================== # Phụ âm đầu VALID_ONSETS = [ "b", "c", "ch", "d", "đ", "g", "gh", "gi", "h", "k", "kh", "l", "m", "n", "ng", "ngh", "nh", "p", "ph", "q", "r", "s", "t", "th", "tr", "v", "x" ] # Nguyên âm VALID_NUCLEI = [ "a", "ă", "â", "e", "ê", "i", "o", "ô", "ơ", "u", "ư", "y", "ia", "iê", "ya", "ya", "ua", "uô", "ưa", "ươ", "ai", "ao", "au", "ay", "âu", "ây", "eo", "êu", "ia", "iê", "yê", "oi", "ôi", "ơi", "ua", "uô", "ươ", "ưu", "uy", "uya" ] # Phụ âm cuối VALID_CODAS = ["c", "ch", "m", "n", "ng", "nh", "p", "t"] # ===== Hàm kiểm tra viết tắt ===== def is_abbreviation(word: str) -> bool: """ Trả về True nếu từ KHÔNG phải âm tiết tiếng Việt chuẩn, tức là có khả năng là viết tắt. Quy tắc: 1. Không có nguyên âm hoặc nguyên âm không hợp lệ -> viết tắt 2. Phụ âm đầu không hợp lệ -> viết tắt 3. Phụ âm cuối không hợp lệ -> viết tắt 4. Nhiều hơn 3 phần (đầu - nguyên âm - cuối) -> viết tắt """ w = word.lower() w = re.sub(r'[^a-zăâêôơưđ]', '', w) if not w: return True # 1. Tìm phụ âm đầu onset = None for o in sorted(VALID_ONSETS, key=len, reverse=True): if w.startswith(o): onset = o break rest = w[len(onset):] if onset else w if onset is None and rest and rest[0] not in "aeiouyăâêôơư": return True # phụ âm đầu không hợp lệ # 2. Tìm phụ âm cuối coda = None for c in sorted(VALID_CODAS, key=len, reverse=True): if rest.endswith(c): coda = c break nucleus = rest[:-len(coda)] if coda else rest # 3. Kiểm tra nguyên âm if not nucleus: return True if nucleus not in VALID_NUCLEI: return True # 4. Kiểm tra số phần parts = [p for p in [onset, nucleus, coda] if p] if len(parts) > 3: return True return False # =============================== # 2. Words # =============================== # ===== Hàm chuẩn hóa từ ====================== def normalize_word(w: str) -> str: return re.sub(r'[^A-Za-zÀ-ỹĐđ0-9]', '', w) # ===== Hàm so sánh độ tương đồng ============= def similar(a, b): return SequenceMatcher(None, a, b).ratio() # ===== Hàm chuyển số La Mã =================== def is_roman(s): return bool(re.fullmatch(r'[IVXLC]+', s)) # ===== Chuyển số La Mã sang số Ả Rập ========= def roman_to_int(s): roman_numerals = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100} result, prev = 0, 0 for c in reversed(s): val = roman_numerals.get(c, 0) if val < prev: result -= val else: result += val prev = val return result # ===== Hàm loại bỏ khoảng trắng thừa ========= def strip_extra_spaces(s: str) -> str: if not isinstance(s, str): return s return re.sub(r'\s+', ' ', s).strip() def merge_txt(RawDataDict, JsonKey, JsonField): paragraphs = RawDataDict.get(JsonKey, []) merged = "\n".join(p.get(JsonField, "").strip() for p in paragraphs if p.get(JsonField)) merged = re.sub(r"\n{2,}", "\n", merged.strip()) return merged