Last active
May 7, 2019 04:23
-
-
Save behitek/d29242ea1a8b999e5c4c8982a4599732 to your computer and use it in GitHub Desktop.
Chuyển số viết thành số đọc sử dụng C++/Python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://daynhauhoc.com/t/share-code-doc-so-thanh-chu-so-lon-bao-nhieu-cung-can-tat/62701/ | |
#include <iostream> | |
#include <string> | |
#include <algorithm> | |
#include <exception> | |
#include <cassert> | |
#ifdef __unix__ | |
#include <clocale> | |
#elif defined _WIN32 || defined _WIN64 | |
#include <fcntl.h> //_O_WTEXT | |
#include <io.h> //_setmode() | |
#endif | |
const std::wstring CHU_SO[] = { | |
L"không", L"một", L"hai", L"ba", L"bốn", | |
L"năm", L"sáu", L"bảy", L"tám", L"chín" | |
}; | |
const std::wstring MUOIF = L"mười"; //muoi` co' dau' | |
const std::wstring MUOI = L"mươi"; | |
const std::wstring TRAM = L"trăm"; | |
const std::wstring NGAN_TR[] = { L"nghìn", L"triệu" }; | |
const std::wstring TY = L"tỷ"; | |
const std::wstring MOTS = L"mốt"; //mot' co dau sac | |
const std::wstring TU = L"tư"; //tu | |
const std::wstring LAM = L"lăm"; //lam | |
const std::wstring LINH = L"linh"; | |
const wchar_t SPACE = L' '; | |
const std::wstring COMMA = L", "; | |
std::wstring toVnStr(const std::string& num); | |
int main() | |
{ | |
#ifdef __unix__ | |
setlocale(LC_ALL, ""); | |
#elif defined _WIN32 || defined _WIN64 | |
setmode(fileno(stdout), _O_WTEXT); //needed for output | |
setmode(fileno(stdin), _O_WTEXT); //needed for input | |
#endif | |
for (int i = 0; i < 1000; i++){ | |
std::string s = std::to_string(i); | |
std::wcout << s.c_str() << " = " << toVnStr(s) << "\n"; | |
} | |
} | |
std::wstring toVnStrLt100(const std::string& num) | |
{ | |
if (num.size() == 1) return CHU_SO[num[0] - '0']; | |
auto result = num[0] == '1' ? MUOIF : (CHU_SO[num[0] - '0'] + SPACE + MUOI); | |
if (num[1] == '0') return result; | |
result += SPACE; | |
if (num[1] == '1' && num[0] != '1') result += MOTS; | |
else if (num[1] == '4' && num[0] != '1') result += TU; | |
else if (num[1] == '5') result += LAM; | |
else result += CHU_SO[num[1] - '0']; | |
return result; | |
} | |
std::wstring toVnStrLt1000(const std::string& num) | |
{ | |
if (num.size() < 3) return toVnStrLt100(num); | |
auto result = CHU_SO[num[0] - '0'] + SPACE + TRAM; | |
if (num[1] == '0' && num[2] == '0') //[0-9]00 | |
return num[0] == '0' ? std::wstring{} : result; | |
if (num[1] == '0') //[1-9]0[1-9] | |
return result + SPACE + LINH + SPACE + CHU_SO[num[2] - '0']; | |
return result + SPACE + toVnStrLt100(num.substr(1)); | |
} | |
std::wstring toVnStrLt1e9(const std::string& num) | |
{ | |
if (num.size() < 4) return toVnStrLt1000(num); | |
int splitIndex = num.size() % 3; | |
if (!splitIndex) splitIndex = 3; | |
auto left = toVnStrLt1e9(num.substr(0, splitIndex)); | |
auto right = toVnStrLt1e9(num.substr(splitIndex)); | |
if (left.empty() && right.empty()) return std::wstring{}; | |
auto const& hang = NGAN_TR[(num.size() - splitIndex) / 3 - 1]; | |
if (left.empty()) return CHU_SO[0] + SPACE + hang + SPACE + right; | |
if (right.empty()) return left + SPACE + hang; | |
return left + SPACE + hang + SPACE + right; | |
} | |
std::wstring toVnStrAbitrary(const std::string& num) | |
{ | |
if (num.size() < 10) return toVnStrLt1e9(num); | |
int splitIndex = num.size() % 9; | |
if (!splitIndex) splitIndex = 9; | |
auto left = toVnStrLt1e9(num.substr(0, splitIndex)); | |
auto right = toVnStrAbitrary(num.substr(splitIndex)); | |
if (left.empty()) return right; | |
auto hang = TY; | |
for (auto i = (num.size() - splitIndex) / 9; i-->1; hang += SPACE + TY); | |
if (right.empty()) return left + SPACE + hang; | |
return left + SPACE + hang + COMMA + right; | |
} | |
std::string stripZeros(const std::string& s, size_t z=0) | |
{ | |
while (z < s.size() && s[z] == '0') ++z; | |
return s[z-1] == '0' ? s.substr(z) : s; | |
} | |
std::wstring toVnStr(const std::string& num) | |
{ | |
if (std::any_of(begin(num), end(num), [](auto c) { return !isdigit(c); })) | |
throw std::invalid_argument("Input string must consist of digits (0-9) only."); | |
auto s = stripZeros(num); | |
return toVnStrAbitrary(s.empty() ? "0" : s); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# https://daynhauhoc.com/t/share-code-doc-so-thanh-chu-so-lon-bao-nhieu-cung-can-tat/62701/ | |
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)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment