SaigonTech Vault
Loại: knowledge-doc 2026-09-29 active #wiki-import

Tuần 1: 2022/08/11

A.Huy (currency_to_text.py)

yêu cầu

number to text,

sửa lại hàm print_number hoặc refactor lại toàn bộ code để đúng cho mấy trường hợp: mốt, lăm, hăm... (bow)

Bug hiện tại

123455000 -> "một trăm hai mươi ba triệu bốn trăm năm mươi năm nghìn  đồng"
123421000 -> "một trăm hai mươi ba triệu bốn trăm hai mươi một nghìn  đồng"

source hiện tại

arr1 = {
    "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",
}
arr2 = {
    "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",
}

arr3 = {
    "1": "một trăm",
    "2": "hai trăm",
    "3": "ba trăm",
    "4": "bốn trăm",
    "5": "năm trăm",
    "6": "sáu trăm",
    "7": "bảy trăm",
    "8": "tám trăm",
    "9": "chín trăm",
}


def print_2(number, dv='đồng', sup='lẻ'):
    ret = ""
    if number < 10 and sup:
        ret += sup
    f = number // 10
    l = number % 10
    if f != 0:
        ret += arr2[str(f)]
    if l != 0:
        ret += f" {arr1[str(l)]}"
    return f"{ret} {dv}" if dv else f"{ret}"


def print_3(number, dv='nghìn'):
    ret = ""
    f = number // 100
    l = number % 100
    if f != 0:
        ret += arr3[str(f)]
    if l != 0:
        ret += f" {print_2(l, dv=None)}"
    return f"{ret} {dv}" if dv else f"{ret}"


def print_number(number):
    f = number // 1000000
    m = (number % 1000000) // 1000
    l = (number % 1000000) % 1000
    if f == 0:
        raise Exception("invalid number")
    if m == 0:
        raise Exception("invalid number")
    if f > 100:
        fp = print_3(f, dv="triệu")
    else:
        fp = print_2(f, dv="triệu")

    mp = print_3(m, dv='nghìn')
    lp = print_3(l, dv='đồng')
    return f"{fp} {mp} {lp}"

Giải pháp (Khoa)

Cách làm: Đọc từng số xong rồi giáp lại thành chuỗi cuối cùng

Cần update lại cho các trường hợp đặc biệt của số 1, 5 và số 0

_digits = ['', 'một', 'hai', 'ba', 'bốn', 'năm', 'sáu', 'bảy', 'tám', 'chín']
_units = ['đồng', 'mươi', 'trăm', 'ngàn', 'mươi', 'trăm', 'triệu', 'mươi', 'trăm', 'tỷ']

_special_units = {
    0: {0:'', 1:'', 2:'', 3:'ngàn', 4:'', 5:'', 6:'triệu', 7:'', 8:'', 9:'tỷ', 13: 'ngàn', 14:'lẻ', 15:'', 16:'triệu', 17:'lẻ'},
    1: {13: 'mốt ngàn', 16: 'mốt triệu', 4: 'mười', 7: 'mười'},
    5: {13: 'lăm ngàn', 16: 'lăm triệu'},
}

class VNum:
    def __init__(self, value, unit, before=None, after=None):
        self.value = value
        self.unit = unit
        self.before = before
        self.after = after


    def __str__(self) -> str:
        if self.unit <= 2:
            return ''

        if self.value == 1:
            i = 10 if (self.before is not None) and (self.before > 1) else 0
            s = _special_units[1].get(i + self.unit)
            if s is not None: return s

        if self.value == 5:
            i = 10 if self.before else 0
            s = _special_units[5].get(i + self.unit)
            if s is not None: return s

        if self.value == 0:
            i = 10 if self.before and self.after else 0
            s = _special_units[0].get(i + self.unit)
            if s is not None: return s

        return f"{_digits[self.value]} {_units[self.unit]}"

def parse(n):
    digits = [int(d) for d in list(str(n))]
    last_index = len(digits) - 1
    v_nums = [str(VNum(digit, last_index - index, digits[index-1] if index > 0 else None, digits[index+1] if index < last_index else None)) for index, digit in enumerate(digits)]
    v_nums = [num for num in v_nums if num != '']
    return ' '.join(v_nums)