Share Code đọc số thành chữ, - số lớn bao nhiêu cũng cân tất

c-sharp
python
c++

(HK boy) #21

Code của mình:

7 lần if (đọc 24 là hai mươi bốn):

6 lần if (đọc 24 là hai mươi tư):


(Tiến Nguyễn) #22

Code simple nhưng vẫn phải đáp ứng đủ yêu cầu nhé. Chứ simple thanh niên hiểu theo ý gì thế? simple là tiểu học? wtf?


(HK boy) #23

Case này em thấy lởm lởm sao ấy ạ, bình thường nếu như có 1 lớp nào đó toàn 0 thì bỏ qua luôn chứ không ai đọc là không đơn vị/nghìn/triệu/tỉ đâu ạ.


(Tao Không Ngu.) #24

Có ai quy tắc đọc chuẩn không ?


(‏) #25

Thì cái ví dụ trên là học sinh lớp 4 nó đọc số thành chữ mà biết đọc lăm, mốt, tư, mười một, v.v… viết code đơn giản cũng phải đọc đc như mấy bé lớp 4 chứ. Đơn giản mà đọc thua lớp 4 thì là code đọc 125 thành “một hai năm” luôn cho rồi, 4-5 dòng siêu đơn giản


(‏) #26

Thì mình cũng phải gg “không nghìn” có ngoặc kép để tìm xem có ai đọc như vậy ko, thì lòi ra cái trang trên nó giải bài tập mấy bé lớp 4 nó đọc không nghìn…


(HK boy) #27

Giải bài tập cũng có trăm nghìn trang anh ơi. Follow sách giáo khoa lớp 4 thôi…


(‏) #28

Tạo cái option cho user lựa chọn luôn là khỏe nhất


(‏) #29

chuyển qua Python3 cho nó dễ, linh lẻ, không nghìn, lăm nhăm gì chơi tuốt

class NumToVnStr:
    def __init__(self, mươi='mươi', nghìn='nghìn', tư='tư', lăm='lăm', linh='linh', tỷ='tỷ', đọc_số_rỗng=True):
        self.chữ_số = ('không', 'một', 'hai', 'ba', 'bốn', 'năm', 'sáu', 'bảy', 'tám', 'chín', 'mười')
        self.mươi = mươi
        self.trăm = 'trăm'
        self.nghìn = nghìn
        self.triệu = 'triệu'
        self.tỷ = tỷ
        self.mốt = 'mốt'
        self.tư = tư
        self.lăm = lăm
        self.linh = linh
        self.đọc_số_rỗng = đọc_số_rỗng
    def to_vn_str(self, s):
        return self._arbitrary(s.lstrip('0'))
    def _int(self, c):
        return ord(c) - ord('0') if c else 0
    def _LT1e2(self, s):
        if len(s) <= 1: return self.chữ_số[self._int(s)]
        if s[0] == '1':
            ret = self.chữ_số[10]
        else:
            ret = self.chữ_số[self._int(s[0])]
            if self.mươi: ret += ' ' + self.mươi
            elif s[1] == '0': ret += ' mươi'
        if s[1] != '0':
            ret += ' '
            if   s[1] == '1' and s[0] != '1': ret += self.mốt
            elif s[1] == '4' and s[0] != '1': ret += self.tư
            elif s[1] == '5': ret += self.lăm
            else: ret += self.chữ_số[self._int(s[1])]
        return ret
    def _LT1e3(self, s):
        if len(s) <= 2: return self._LT1e2(s)
        if s == '000': return ''
        ret = self.chữ_số[self._int(s[0])] + ' ' + self.trăm
        if s[1] != '0':
            ret += ' ' + self._LT1e2(s[1:])
        elif s[2] != '0':
            ret += ' ' + self.linh + ' ' + self.chữ_số[self._int(s[2])]
        return ret
    def _LT1e9(self, s):
        if len(s) <= 3: return self._LT1e3(s)
        if s == '000000' or s == '000000000': return ''
        mid = len(s) % 3 if len(s) % 3 else 3
        left, right = self._LT1e3(s[:mid]), self._LT1e9(s[mid:])
        hang = self.nghìn if len(s) <= 6 else self.triệu
        if not left:
            if not self.đọc_số_rỗng: return right
            else: return self.chữ_số[0] + ' ' + hang + ' ' + right
        if not right: return left + ' ' + hang
        return left + ' ' + hang + ' ' + right
    def _arbitrary(self, s):
        if len(s) <= 9: return self._LT1e9(s)
        mid = len(s) % 9 if len(s) % 9 else 9
        left, right = self._LT1e9(s[:mid]), self._arbitrary(s[mid:])
        hang = ' '.join([self.tỷ] * ((len(s) - mid) // 9))
        if not left:
            if not self.đọc_số_rỗng: return right
            elif right: return self.chữ_số[0] + ' ' + hang + ', ' + right
            else: return right
        if not right: return left + ' ' + hang
        return left + ' ' + hang + ', ' + right

if __name__ == '__main__':
    test_cases_1 = (
        "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
        "10", "11", "12", "20", "21", "22", "24", "90", "91", "97",
        "300", "999", "121", "215", "5121", "39500",
        "1025217", "51105500", "51000000", "999999999",
        "5120625952200", "12000000000000000000", "18446744073709551615",
        "18000000000709551615", "11000000000",
        "1000015", "1002015", "1000000024",
        "03215", "", "0000", "00001", "00100",
        "1844674407370955161518000000000000000000709551615",
        "0321", "000345", "15", "40430203", "3209", "3500", "3901", "21",
        "3005", "3055", "9031", "9330",
        "9000005", "9001005",
    )
    test_cases_2 = (
        ("32000000", "ba mươi hai triệu"),
        ("32516000", "ba mươi hai triệu năm trăm mười sáu nghìn"),
        ("32516497", "ba mươi hai triệu năm trăm mười sáu nghìn bốn trăm chín mươi bảy"),
        ("834291712", "tám trăm ba mươi tư triệu hai trăm chín mươi mốt nghìn bảy trăm mười hai"),
        ("308250705", "ba trăm linh tám triệu hai trăm năm mươi nghìn bảy trăm linh năm"),
        ("500209037", "năm trăm triệu hai trăm linh chín nghìn không trăm ba mươi bảy"),
        ("7312836", "bảy triệu ba trăm mười hai nghìn tám trăm ba mươi sáu"),
        ("57602511", "năm mươi bảy triệu sáu trăm linh hai nghìn năm trăm mười một"),
        ("351600307", "ba trăm năm mươi mốt triệu sáu trăm nghìn ba trăm linh bảy"),
        ("900370200", "chín trăm triệu ba trăm bảy mươi nghìn hai trăm"),
        ("400070192", "bốn trăm triệu không trăm bảy mươi nghìn một trăm chín mươi hai"),
        ("10250214", "mười triệu hai trăm năm mươi nghìn hai trăm mười bốn"),
        ("253564888", "hai trăm năm mươi ba triệu năm trăm sáu mươi tư nghìn tám trăm tám mươi tám"),
        ("400036105", "bốn trăm triệu không trăm ba mươi sáu nghìn một trăm linh năm"),
        ("700000231", "bảy trăm triệu không nghìn hai trăm ba mươi mốt"),
    )

    custom_converter = NumToVnStr(đọc_số_rỗng=True, linh='lẻ', tư='bốn', nghìn='ngàn', mươi=False, tỷ='tỉ', lăm='nhăm')
    for i in test_cases_1:
        print('{} = {}'.format(i, custom_converter.to_vn_str(i)))
    default_converter = NumToVnStr()
    for test_case in test_cases_2:
        i, o = test_case
        assert default_converter.to_vn_str(i) == o
        print('\n{}\n{}\n{}'.format(i, default_converter.to_vn_str(i), o))

output

0 = không
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
10 = mười
11 = mười một
12 = mười hai
20 = hai mươi
21 = hai mốt
22 = hai hai
24 = hai bốn
90 = chín mươi
91 = chín mốt
97 = chín bảy
300 = ba trăm
999 = chín trăm chín chín
121 = một trăm hai mốt
215 = hai trăm mười nhăm
5121 = năm ngàn một trăm hai mốt
39500 = ba chín ngàn năm trăm
1025217 = một triệu không trăm hai nhăm ngàn hai trăm mười bảy
51105500 = năm mốt triệu một trăm lẻ năm ngàn năm trăm
51000000 = năm mốt triệu
999999999 = chín trăm chín chín triệu chín trăm chín chín ngàn chín trăm chín chín
5120625952200 = năm ngàn một trăm hai mươi tỉ, sáu trăm hai nhăm triệu chín trăm năm hai ngàn hai trăm
12000000000000000000 = mười hai tỉ tỉ
18446744073709551615 = mười tám tỉ tỉ, bốn trăm bốn sáu triệu bảy trăm bốn bốn ngàn không trăm bảy ba tỉ, bảy trăm lẻ chín triệu năm trăm năm mốt ngàn sáu trăm mười nhăm
18000000000709551615 = mười tám tỉ tỉ, không tỉ, bảy trăm lẻ chín triệu năm trăm năm mốt ngàn sáu trăm mười nhăm
11000000000 = mười một tỉ
1000015 = một triệu không ngàn không trăm mười nhăm
1002015 = một triệu không trăm lẻ hai ngàn không trăm mười nhăm
1000000024 = một tỉ, không triệu không ngàn không trăm hai bốn
03215 = ba ngàn hai trăm mười nhăm
 = không
0000 = không
00001 = một
00100 = một trăm
1844674407370955161518000000000000000000709551615 = một ngàn tám trăm bốn bốn tỉ tỉ tỉ tỉ tỉ, sáu trăm bảy bốn triệu bốn trăm lẻ bảy ngàn ba trăm bảy mươi tỉ tỉ tỉ tỉ, chín trăm năm nhăm triệu một trăm sáu mốt ngàn năm trăm mười tám tỉ tỉ tỉ, không tỉ tỉ, không tỉ, bảy trăm lẻ chín triệu năm trăm năm mốt ngàn sáu trăm mười nhăm
0321 = ba trăm hai mốt
000345 = ba trăm bốn nhăm
15 = mười nhăm
40430203 = bốn mươi triệu bốn trăm ba mươi ngàn hai trăm lẻ ba
3209 = ba ngàn hai trăm lẻ chín
3500 = ba ngàn năm trăm
3901 = ba ngàn chín trăm lẻ một
21 = hai mốt
3005 = ba ngàn không trăm lẻ năm
3055 = ba ngàn không trăm năm nhăm
9031 = chín ngàn không trăm ba mốt
9330 = chín ngàn ba trăm ba mươi
9000005 = chín triệu không ngàn không trăm lẻ năm
9001005 = chín triệu không trăm lẻ một ngàn không trăm lẻ năm

32000000
ba mươi hai triệu
ba mươi hai triệu

32516000
ba mươi hai triệu năm trăm mười sáu nghìn
ba mươi hai triệu năm trăm mười sáu nghìn

32516497
ba mươi hai triệu năm trăm mười sáu nghìn bốn trăm chín mươi bảy
ba mươi hai triệu năm trăm mười sáu nghìn bốn trăm chín mươi bảy

834291712
tám trăm ba mươi tư triệu hai trăm chín mươi mốt nghìn bảy trăm mười hai
tám trăm ba mươi tư triệu hai trăm chín mươi mốt nghìn bảy trăm mười hai

308250705
ba trăm linh tám triệu hai trăm năm mươi nghìn bảy trăm linh năm
ba trăm linh tám triệu hai trăm năm mươi nghìn bảy trăm linh năm

500209037
năm trăm triệu hai trăm linh chín nghìn không trăm ba mươi bảy
năm trăm triệu hai trăm linh chín nghìn không trăm ba mươi bảy

7312836
bảy triệu ba trăm mười hai nghìn tám trăm ba mươi sáu
bảy triệu ba trăm mười hai nghìn tám trăm ba mươi sáu

57602511
năm mươi bảy triệu sáu trăm linh hai nghìn năm trăm mười một
năm mươi bảy triệu sáu trăm linh hai nghìn năm trăm mười một

351600307
ba trăm năm mươi mốt triệu sáu trăm nghìn ba trăm linh bảy
ba trăm năm mươi mốt triệu sáu trăm nghìn ba trăm linh bảy

900370200
chín trăm triệu ba trăm bảy mươi nghìn hai trăm
chín trăm triệu ba trăm bảy mươi nghìn hai trăm

400070192
bốn trăm triệu không trăm bảy mươi nghìn một trăm chín mươi hai
bốn trăm triệu không trăm bảy mươi nghìn một trăm chín mươi hai

10250214
mười triệu hai trăm năm mươi nghìn hai trăm mười bốn
mười triệu hai trăm năm mươi nghìn hai trăm mười bốn

253564888
hai trăm năm mươi ba triệu năm trăm sáu mươi tư nghìn tám trăm tám mươi tám
hai trăm năm mươi ba triệu năm trăm sáu mươi tư nghìn tám trăm tám mươi tám

400036105
bốn trăm triệu không trăm ba mươi sáu nghìn một trăm linh năm
bốn trăm triệu không trăm ba mươi sáu nghìn một trăm linh năm

700000231
bảy trăm triệu không nghìn hai trăm ba mươi mốt
bảy trăm triệu không nghìn hai trăm ba mươi mốt

edit: sửa mấy lỗi sai + sửa thành cái đọc rỗng option :astonished:


(HK boy) #30

Mới update code cho giới hạn “tỉ tỉ tỉ tỉ tỉ…” giống như anh tntxtnt =))

one_digit = ["không", "một", "hai", "ba", "bốn", "năm", "sáu", "bảy", "tám", "chín"]
units = ["", " mốt", " hai", " ba", " bốn", " lăm", " sáu", " bảy", " tám", " chín"]
tens = ["linh", "mười"] + [x + " mươi" for x in ["hai", "ba", "bốn", "năm", "sáu", "bảy", "tám", "chín"]]
hundreds = [x + " trăm" for x in one_digit]
bigger = ["", " nghìn", " triệu"]


def read_class(s):
	n = int(s)
	if len(s) == 1:
		return one_digit[n]
	elif len(s) == 2:
		return tens[n//10] + units[n%10]
	else:  # len(s) == 3
		if s == '000':
			return ''
		elif (n//10)%10 == 0:  # x0y
			if n % 10 == 0:  # x00
				return hundreds[n//100]
			else:
				return hundreds[n//100] + ' ' + tens[(n//10)%10] + ' ' + one_digit[n%10]
		else:  # xyz
			return hundreds[n//100] + ' ' + tens[(n//10)%10] + units[n%10]


def read_billion_group(s):
	classes = []
	for i in range(len(s)-1, 1, -3):
		classes.append(s[i-2:i+1])
	
	if len(s) % 3 != 0:
		classes.append(s[:len(s)%3])
	
	res = ''
	for i in range(len(classes)):
		named_class = read_class(classes[i])
		if named_class != '':
			res = named_class + bigger[i] + (' ' * (res != '')) + res

	return res


while True:
	try:
		s = input()
	except:
		break

	s = s.lstrip('0').rstrip('\n')
	billion_groups = []
	for i in range(len(s)-1, 7, -9):
		billion_groups.append(s[i-8:i+1])
	
	if len(s) % 9 != 0:
		billion_groups.append(s[:len(s)%9])

	res = ''
	for i in range(len(billion_groups)-1, -1, -1):
		group_name = read_billion_group(billion_groups[i])

		if group_name != '':
			res += group_name + ' tỉ' * i + (', ' * (i != 0))

	print(res)

(‏) #31

lên tới tỉ tỉ tỉ tỉ là ko biết đọc làm sao, gu gồ cũng ko thấy cách đọc @_@ nên đành chế đại =)


(HK boy) #32

Nghe thời sự thấy “ba mươi tư nghìn tỉ” suốt, chắc là tỉ tỉ tỉ cũng đúng :joy:


(‏) #33

làm 1 cái class cho mấy cái biến global thành biến trong class, rồi từ đó tha hồ custom. Đặt tên biến tiếng Việt luôn, kệ mẹ mấy thằng tây lông đọc code mình :joy:


(HK boy) #34

Đọc kĩ thấy code anh hay quá :joy: người dùng tha hồ nhập =)) Ơ tại sao anh lại cho “hai mốt” kia… Cũng phải cho user thích “hai mốt” hay “hai mươi mốt” luôn chứ =))

Trẻ trâu tí, em mới code xong code từ đọc số thành số, có test thử số “tỉ tỉ tỉ tỉ tỉ” của anh và thấy ngon ăn =))

bigger = ["tỉ tỉ", "triệu tỉ", "nghìn tỉ", "tỉ", "triệu", "nghìn"]
base = { "": 1, "nghìn": 1000, "triệu": 10**6 }
one_digit = { "không": 0, "một": 1, "hai": 2, "ba": 3, "bốn": 4, "năm": 5, "sáu": 6, "bảy": 7, "tám": 8, "chín": 9 }
units = { "": 0, "một": 1, "mốt": 1, "hai": 2, "ba": 3, "bốn": 4, "tư": 4, "lăm": 5, "nhăm": 5, "sáu": 6, "bảy": 7, "tám": 8, "chín": 9 }

def num_class(s):
	# x trăm
	# x trăm linh z
	# x trăm mười z
	# x trăm y mươi
	# x trăm y mươi z

	# z
	# mười z
	# y mươi
	# y mươi z

	if len(s) == 0:
		return 0

	words = s.split(' ')

	if len(words) == 1:  # z
		return one_digit[words[0]]

	elif words[1] == 'trăm':  # xyz
		if len(words) == 2:  # x00
			return one_digit[words[0]]*100
		
		if words[2] == 'linh' or words[2] == 'lẻ':  # x0z
			return one_digit[words[0]]*100 + one_digit[words[3]]

		elif words[2] == 'mười':  # x1z
			return one_digit[words[0]]*100 + 10 + units[words[3]]

		else:
			if len(words) == 4:  # xy0
				return one_digit[words[0]]*100 + one_digit[words[2]]*10
			else:  # xyz
				return one_digit[words[0]]*100 + one_digit[words[2]]*10 + units[words[4]]

	else:  # yz
		if words[0] == 'mười':  # x1z
			return 10 + units[words[1]]

		else:
			if len(words) == 2:  # xy0
				return one_digit[words[0]]
			else:  # xyz
				return one_digit[words[0]]*10 + units[words[2]]


def find_biggest_billion(s):
	l = 0
	r = len(s.split(' '))

	for stupid_variable in range(64):
		if r - l < 2:
			if r < l:
				return -1
			else:
				if s.find(' tỉ' * r) != -1:
					return r

				elif s.find(' tỉ' * l) != -1:
					return l

				else:
					return -1

		mid = (l + r) // 2
		if s.find(' tỉ' * mid) != -1:
			if s.find(' tỉ' * (mid+1)) == -1:
				return mid
			else:
				l = mid
		else:
			r = mid


def num_billion_group(s):
	res = 0
	for class_name in bigger:
		loc_class_pos = s.find(class_name)

		if loc_class_pos != -1:
			res += num_class(s[:loc_class_pos-1]) * base[class_name]
			s = s[loc_class_pos+len(class_name)+1:]

	res += num_class(s)
	return res


while True:
	try:
		s = input()
	except:
		break

	# s_value = s
	# một nghìn tám trăm bốn mươi bốn tỉ tỉ tỉ tỉ tỉ sáu trăm bảy mươi bốn triệu bốn trăm linh bảy nghìn ba trăm bảy mươi tỉ tỉ tỉ tỉ chín trăm năm mươi lăm triệu một trăm sáu mươi mốt nghìn năm trăm mười tám tỉ tỉ tỉ bảy trăm linh chín triệu năm trăm năm mươi mốt nghìn sáu trăm mười lăm

	group_len = find_biggest_billion(s)
	nested_billion_group = [''] * (group_len+1)

	for nested_billion in range(group_len, 0, -1):
		if s.find(' tỉ' * nested_billion) != -1:
			x = s[:s.find(' tỉ' * nested_billion)]
			nested_billion_group[nested_billion] = x
			s = s[s.find(' tỉ' * nested_billion)+len(' tỉ') * nested_billion:].lstrip(' ')

	if s != '':
		nested_billion_group[0] = s

	result = 0
	for x in reversed(nested_billion_group):
		result = result * 10**9 + num_billion_group(x)

	print(result)

Em lười code lại thành class quá =))


(Tiến Nguyễn) #35

Vãi thanh niên, thanh niên comment một đoạn code dài ngoàng bên trên. Xong tôi comment simple thôi. Simple là đơn giản ok. Nhưng đơn giản phải đáp ứng được mọi yêu cầu. Có nghĩa nó phải đọc đúng mọi case nhưng code vẫn đơn giản dẽ hiểu. Chứ simple như ý thanh niên thì thôi khỏi đọc luôn. Để nguyên là số cho nó lành. :slight_smile:


(Tiến Nguyễn) #36

“ba mươi tư nghìn tỉ” và “tỉ tỉ tỉ” là 2 số khác nhau hoàn toàn nhé thanh niên.


(HK boy) #37

Ai chả biết. Mình chỉ muốn nói là quy tắc chung thôi.


(‏) #38

NumToVnStr(không_nghìn=False, linh='lẻ', tư='bốn', nghìn='ngàn', mươi=False, tỷ='tỉ', lăm='nhăm')

hai mươi mốt là default rồi, thích bỏ “mươi” đi thì thêm mươi=False vô khi khởi tạo object converter, chỉ có “triệu” “trăm” “mốt” là ko custom được thôi. Tại đếm nhanh thì đọc hai mốt hai hai hai ba bỏ qua mươi cũng được, nên cho nó là optional luôn :kissing:

chắc cũng phải thêm option ghi “…, không tỷ tỷ, không tỷ, …” nữa thay vì bỏ qua, đọc như vậy mới rõ ràng như không triệu không ngàn @_@


(HK boy) #39

Hay là gộp vào 1 option đọc_lớp_rỗng luôn ạ?

option này = True -> không tỉ, không triệu, không nghìn,…
option này = False -> ignore những lớp rỗng hết


(‏) #40

đơn giản nhưng test case fail tùm lum thì sao được :kissing: 3005 đọc là ba nghìn năm ai lại đọc như thế.


83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?