轉換目標

1. 如果是單純的

1024 -> 一零二四 -> 1024 這種轉換實在太過簡單

2. 如果要轉換金額,有線上工具可用

1024 -> 壹仟零貳拾肆圓整

3. 本篇要轉換的是中文數字/阿拉伯數字,也就是會加上萬、千、百、十等字

1024 -> 一千零二十四 -> 1024

且不會加上多餘的字

100000 -> 十萬  -> 100000

 

阿拉伯數字 -> 中文數字

中文數字寫法

參考 Wiki 之中文數字

1. 個位以前的 0 要寫出來,但連續的 0 只要寫一個

2. 零一二三四五六七八九 這幾個字各代表 0~9

3. 數字從右(小位數,如果代表 a*10^b, 則是說小的 b) 到左每隔 4 個切成一群,
從第一群到之後依序加上 萬、億、兆...(再後面的參考 Wiki)

4. 承 #3, 每群中四個數字從右到左的第 2 到第 4 個數字依序加上 十、百、千

 

編程

number-to-chinese-numerals    

(以上圖 i 是迴圈從左往右依序拜訪

revi 則是反向的 i

si 是 revi % 4

bi 是 revi / 4)

 

1. 將小寫依照間隔分開
像數字通常間隔 3 就有一個逗號 123,123,456
中文數字則是間隔 4 就有一個 萬, 億, 兆, ...

可以得到大的間隔 萬, 億, 兆
小的間隔 千, 百, 十

2. 從左至右,小間隔中,檢視每位元,非零則
a. 如果之前有一個或多個零,先加上 零

b. 增加 ㄧ~九 數字

c. si = 1,2,3 則增加 千, 百, 十

3. 從左至右,當遇到大間隔,si = 0, 但 bi != 0
a. 增加 萬, 億, 兆 字元

 

中文數字 -> 阿拉伯數字

編程

例如
"一億零一百二十三萬"

1. 從左至右,如果是 ㄧ~九,紀錄數值到 val

2. 如果是小間隔字元 (千, 百, 十),依序儲存 val 到 siNum[] 長度為 4 陣列
"一百二十三" 則儲存為 siNum[1] = 2, siNum[2] = 1, siNum[3] = 0

3. 如果是大間隔字元 (萬, 億, 兆, ...),
a. 如果上次輸出的 10 的 lastBiPower 次方和這次 10 的 biPower 次方差了 4 以上,
輸出 lastBiPower - 4 - biPower 個 0

b. 如果 val 尚未處理,儲存到 siNum[0]

c. 依序將 siNum 從 index 3~0 數值輸出

 

注意事項

1. 可以看得出來,以上 中文數字 -> 數字 規則其實完全不理會 "零"
而是由 小間隔 (千, 百, 十) 或 大間隔字元 (兆, 億, 萬,...) 來知道 10 的 x 次方
算是一個簡單的 parser,不管文法錯誤

2. 數字 -> 中文數字 規則中,只要有連續一個以上的零,按照 Wiki 的講法,應該要加上 "零",
所以如圖的範例 59 2000 1245 應該要念成 五十九億二千萬"零"ㄧ千二百四十五,
但是一般上我們會不念兩千萬的 "零",只要將程式碼中 lastZero = false; 反注解即可得到結果不加零

3. 如果數字開頭是 1,程式碼中不會解讀成 "ㄧ十",而是以 "十" 開頭,但是如果 1 夾在中間,則是念 "ㄧ十"
像 10 0000 會輸出 十萬,810 0000 會輸出 八百一十萬

4. 如果數字開頭是 2,通常在開頭如果是個位數、百位數、或千位數習慣會改念 "兩",
此處程式碼並沒有實作這個項目

5. 程式碼中 num2spell() 函式 只接受標準非負整數,010 或是 1,234 格式不接受

6. spell.txt 要存成 ANSI Encoding 程式才能讀

7. 中文輸入法有兩種 "ㄧ" (短的、斜的),另外一種是 "一" (長的、平的),程式碼是用短的

 

程式碼

http://pastebin.com/ZDKQ0Q2k

程式碼驗證用到的 num.txt

http://pastebin.com/SLL7fgJk

程式碼驗證用到的 spell.txt

http://pastebin.com/XtpwbEnD

 

說明

將 validate(...) 反注解即可驗證正確性

將 FILE_IN, FILE_OUT 和 validate 丟的參數改一下,即可反轉驗證方式

 

arrow
arrow
    全站熱搜

    Shawn 發表在 痞客邦 留言(1) 人氣()