如何将数字转换成口语中的文本串
概述
今天突發奇想, 寫一個將數字轉換成中文字符串的函數. 并不是將 1234 轉成 '1234' , 而是將 1234 轉成 '一千二百三十四'.
本來以為很簡單, 寫下來之后發現還是有些坑的.
嘗試
因為我是在寫完最終版本, 回過頭來整理的這篇文章, 所以中間很多嘗試的步驟會有所遺漏. 以下簡單整理一下. 如果不想看, 可以直接拉到最后, 看最終的成品.
第一次嘗試
在寫之前, 首先要尋找中文說話的規律嘛.
所以我的初步想法是, 將數字的每一位都轉成中文然后拼上對應的權重, so easy. 以下為 Python 實現:
# 數字中文 DIGIT_STR_LIST = ['', '一', '二', '三', '四', '五', '六', '七', '八', '九'] # 權重中文 WIGHT_STR_LIST = ['', '十', '百', '千', '萬', '十萬', '百萬', '千萬', '億']def num_to_str(num):# 保存每一位的內容result_list = []# 遍歷數字的每一位, 將數組轉列表并倒序遍歷for wight, digit in enumerate(reversed(list(str(num)))):digit = int(digit)digit_str = DIGIT_STR_LIST[digit] if digit < len(DIGIT_STR_LIST) else ''wight_str = WIGHT_STR_LIST[wight] if wight < len(WIGHT_STR_LIST) else ''# 結果拼接result_list.append(digit_str + wight_str)# 將結果倒序拼接result_list.reverse()return "".join(result_list)OK, 寫的很流暢, 也很簡單, 嘗試一下.
- 傳參: 1234 , 輸出: 一千二百三十四 . 很完美.
- 五位數試一下: 54321. 輸出: 五萬四千三百二十一. nice
- 六位數試一下: 654321 . 輸出: 六十萬五萬四千三百二十一. ???
有問題. 這里問題很明顯了, 我將權重直接拼到了每一位的后邊, 而十萬直接拼上去明顯有問題. 正解應該是六十五萬四千三百二十一.
到這里, 毫無疑問, 一開始思路就錯了, 需要重新改變一下思路了.
第二次嘗試
對于654321這個數字.
十萬位6沒有將十萬直接拼到后邊, 而是和萬位5連起來, 一起組成了六十五萬. 再多一個數字呢? 7654321, 就應該是七百六十五萬. 我貌似發現規律了, 把數字切分為四個一組就可以了.
再看一下位數多一點的數字: 1-2345-6789. 中文是: 一億-二千三百四十五萬-六千七百八十九 嗯, 和我預想得一毛一樣. 大概懂了, 著手改進一下:
# 數字中文 DIGIT_STR_LIST = ['', '一', '二', '三', '四', '五', '六', '七', '八', '九'] # 權重中文 WIGHT_STR_LIST = ['', '十', '百', '千'] # 分組后對應的中文 GROUP_STR_LIST = ['', '萬', '億', '兆']def thousand_list_num_to_str(num_list: list) -> str:"""將4位數字轉成字符串:param num_list: 數字列表, 長度不超過4. 索引和數字對應為: 個十百千:return:"""# 保存每一位的內容result_list = []# 遍歷數字的每一位, 將數組轉列表并倒序遍歷for wight, digit in enumerate(num_list):digit = int(digit)digit_str = DIGIT_STR_LIST[digit] if digit < len(DIGIT_STR_LIST) else ''wight_str = WIGHT_STR_LIST[wight] if wight < len(WIGHT_STR_LIST) else ''# 結果拼接result_list.append(digit_str + wight_str)# 將結果倒序拼接result_list.reverse()return "".join(result_list)def num_to_str(num : int) -> str:"""將數組裝成中文:param num::return:"""# 將數字切割為每四個一組, 分別進行處理num_list = list(str(num))# 這里為了處理長度不是4整數倍的情況, 提前反轉.num_list.reverse()group_num_list = [num_list[i:i+4] for i in range(0, len(num_list), 4)]result_list = []# 遍歷每一組, 并產生對應中文輸出for group, num_list in enumerate(group_num_list):this_num_str = thousand_list_num_to_str(num_list)group_str = GROUP_STR_LIST[group] if group < len(GROUP_STR_LIST) else ''result_list.append(this_num_str + group_str)result_list.reverse()return ''.join(result_list)OK! 現在已經可以應對剛才的情況了. 試一下:
- 654321 -> 六十五萬四千三百二十一
- 321 -> 三百二十一
- 120 -> 一百二十
- 10101010 -> 一千百一十萬一千百一十 納尼???
- 1000 -> 一千百一十 納尼???
很明顯, 問題出在thousand_list_num_to_str 這個函數.
四位數的時候, 0應該是要跳過的.
第三次嘗試
我們對thousand_list_num_to_str函數進行簡單的改進, 遇到零的時候直接跳過, 不進行處理. 改進后如下(只展示了部分改動的地方):
DIGIT_STR_LIST = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']def thousand_list_num_to_str(num_list: list) -> str:"""將4位數字轉成字符串:param num_list: 數字列表, 長度不超過4. 索引和數字對應為: 個十百千:return:"""# 保存每一位的內容result_list = []# 遍歷數字的每一位, 將數組轉列表并倒序遍歷for wight, digit in enumerate(num_list):digit = int(digit)# 0無輸出if digit is 0:continuedigit_str = DIGIT_STR_LIST[digit] if digit < len(DIGIT_STR_LIST) else ''wight_str = WIGHT_STR_LIST[wight] if wight < len(WIGHT_STR_LIST) else ''# 結果拼接result_list.append(digit_str + wight_str)# 將結果倒序拼接result_list.reverse()return "".join(result_list)OK, 再次嘗試.
- 10101010 -> 一千一十萬一千一十 nice!
- 100 -> 一百 nice!
- 1210 -> 一千二百一十
- 1201 -> 一千二百一 納尼??
這里按照思維, 應該是輸出一千二百零一才對. 繼續對thousand_list_num_to_str函數進行加工.
第四次嘗試
這里thousand_list_num_to_str函數要將零輸出, 但是要考慮連續為零的情況(前邊的100). 改動后代碼如下:
def thousand_list_num_to_str(num_list: list) -> str:"""將4位數字轉成字符串:param num_list: 數字列表, 長度不超過4. 索引和數字對應為: 個十百千:return:"""# 保存每一位的內容result_list = []# 遍歷數字的每一位, 將數組轉列表并倒序遍歷for wight, digit in enumerate(num_list):digit = int(digit)if digit is 0:# 個位的0無輸出if wight is 0:continue# 連續0無輸出elif int(num_list[wight-1]) is 0:continue# 直接拼零result_list.append(ZERO_STR)continuedigit_str = DIGIT_STR_LIST[digit] if digit < len(DIGIT_STR_LIST) else ''wight_str = WIGHT_STR_LIST[wight] if wight < len(WIGHT_STR_LIST) else ''#if digit is 0:wight_str = ''# 結果拼接result_list.append(digit_str + wight_str)# 將結果倒序拼接result_list.reverse()return "".join(result_list)OK. 嘗試一下:
- 100 -> 一百
- 1201 -> 一千二百零一 nice
- 101 -> 一百零一
- 1000 -> 一千
- 100000000 -> 一億萬 什么鬼?
后邊怎么多了一個萬?
第五次嘗試
有了處理0的經驗, so easy, num_to_str這個函數呀加上一個對0的處理就好了. 代碼如下(只展示了num_to_str函數):
def num_to_str(num : int) -> str:"""將數組裝成中文:param num::return:"""# 將數字切割為每四個一組, 分別進行處理num_list = list(str(num))# 這里為了處理長度不是4整數倍情況, 提前反轉.num_list.reverse()group_num_list = [num_list[i:i+4] for i in range(0, len(num_list), 4)]result_list = []# 遍歷每一組, 并產生對應中文輸出for group, num_list in enumerate(group_num_list):# 若是0, 跳過if int(''.join(num_list)) is 0:continuethis_num_str = thousand_list_num_to_str(num_list)group_str = GROUP_STR_LIST[group] if group < len(GROUP_STR_LIST) else ''result_list.append(this_num_str + group_str)result_list.reverse()return ''.join(result_list)再次進行嘗試:
- 100000000 -> 一億 nice!!
- 0 -> ??? 我的零呢?
第六次嘗試
這個判斷就粗暴了, 直接在num_to_str的入口處強制判一下0, 改動內容:
ZERO_STR = '零' def num_to_str(num : int) -> str:if num is 0:return ZERO_STR...再來:
- 0 -> 零
- …
經過我的一番測試, 基本完成.
總結
開始有這個想法的時候, 我想著會很簡單, 隨便寫寫咯. 但是當真正開始動手后, 才發現, 事情完全偏離了我的預期. 在寫的過程中, 初版只是個很簡單的版本, 但是在自己嘗試的過程中總是發現各種各樣的問題, 甚至有的時候解決了這個問題, 回頭一測, 發現原來已經改好的問題有出現了, 唉, 果然還是功力太淺啊. too young, too simple, sometimes naive.
我最終還算是磕磕絆絆的寫完了, 不過冥冥之中還是感覺有一些情況沒有考慮到, 無妨, 反正這不過是個一路填坑的過程, 再碰到問題, 改就完了.
至此, 代碼初步完成, 將完整代碼奉上:
# 數字中文 DIGIT_STR_LIST = ['', '一', '二', '三', '四', '五', '六', '七', '八', '九'] # 權重中文 WIGHT_STR_LIST = ['', '十', '百', '千'] # 分組后對應的中文 GROUP_STR_LIST = ['', '萬', '億', '兆'] # 零 ZERO_STR = '零'def thousand_list_num_to_str(num_list: list) -> str:"""將4位數字轉成字符串:param num_list: 數字列表, 長度不超過4. 索引和數字對應為: 個十百千:return:"""# 保存每一位的內容result_list = []# 遍歷數字的每一位, 將數組轉列表并倒序遍歷for wight, digit in enumerate(num_list):digit = int(digit)if digit is 0:# 個位的0無輸出if wight is 0:continue# 連續0無輸出elif int(num_list[wight-1]) is 0:continue# 直接拼零result_list.append(ZERO_STR)continuedigit_str = DIGIT_STR_LIST[digit] if digit < len(DIGIT_STR_LIST) else ''wight_str = WIGHT_STR_LIST[wight] if wight < len(WIGHT_STR_LIST) else ''#if digit is 0:wight_str = ''# 結果拼接result_list.append(digit_str + wight_str)# 將結果倒序拼接result_list.reverse()return "".join(result_list)def num_to_str(num : int) -> str:"""將數組裝成中文:param num::return:"""if num is 0:return ZERO_STR# 將數字切割為每四個一組, 分別進行處理num_list = list(str(num))# 這里為了處理長度不是4整數倍情況, 提前反轉.num_list.reverse()group_num_list = [num_list[i:i+4] for i in range(0, len(num_list), 4)]result_list = []# 遍歷每一組, 并產生對應中文輸出for group, num_list in enumerate(group_num_list):# 若是0, 跳過if int(''.join(num_list)) is 0:continuethis_num_str = thousand_list_num_to_str(num_list)group_str = GROUP_STR_LIST[group] if group < len(GROUP_STR_LIST) else ''result_list.append(this_num_str + group_str)result_list.reverse()return ''.join(result_list)總結
以上是生活随笔為你收集整理的如何将数字转换成口语中的文本串的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql update 联合更新_My
- 下一篇: 23种设计模式之适配器模式