經典題目: 輸入任數字介於 1~999999999 間,並將其轉成中文樣式
ex: 100 => 壹佰
999999999 => 玖億玖仟玖佰玖拾玖萬玖仟玖佰玖拾玖
我的解法思路可以參考誤入C#村的『Java Programmer』經驗分享--LinQ
不過依照我第1~2步的做法所得到的結果
ex: GetAnswer(int 60058905) => 陸仟萬零佰萬零拾萬伍萬捌仟玖佰零拾伍
直覺應該可以直接用LinQ
來對字串做操作來得到正確的中文結果
如果有半夜『熱』到睡不著覺,可挑戰看看這題
:
如何將 1~999999999 間的任意數字,從
『X億X仟萬X佰萬X拾萬X萬X仟X佰X拾X』變成正確的中文輸出
ex: 陸仟萬零佰萬零拾萬伍萬捌仟玖佰零拾伍 => 陸仟零伍萬捌仟玖佰零伍
燒完腦後會比較好入睡
雖然標題有提到『LinQ 有更好的解法嗎?』不過歡迎各路好手參與燒腦
只要限定從『X億X仟萬X佰萬X拾萬X萬X仟X佰X拾X』開始處理中文轉換就行了
感謝參與回答的各位邦友
處理『億、萬』的地方有點亂。
根據 淺水員大 提供的範例,上面的寫法有 Bug
20,0000,1000 -> 貳拾億萬零壹仟
多了一個萬。 (╯‵□′)╯︵┴─┴
只靠 Aggregate 沒辦法處理整組為零的情況
目前網路上的規則有點亂
我大致分為三類
2,0010,1000 -> 貳億零壹拾萬『零』壹仟
2,0000,1000 -> 貳億『零』壹仟
2,0010,1000 -> 貳億零壹拾萬『』壹仟
2,0000,1000 -> 貳億『零』壹仟
2,0010,1000 -> 貳億零壹拾萬『』壹仟
2,0000,1000 -> 貳億『』壹仟
網路上的轉換器普遍使用前兩種規則
Excel 的格式化則使用第三種
上面的程式我是使用規則一來寫
不過看起來應該是 淺水員大 提供的最正規
所以接下來就改用規則二
-> 200101000
-> 2,0010,1000
-> 貳 |零壹拾 |壹仟
-> 貳億|零壹拾萬|壹仟
-> 貳億零壹拾萬壹仟
-> 200001000
-> 2,0000,1000
-> 貳 |零|壹仟
-> 貳億|零|壹仟
-> 貳億零壹仟
-> 2000000000100
-> 2,0000,0000,0100
-> 貳 | x | x |零壹佰
-> 貳兆| x | x |零壹佰
-> 貳兆零壹佰
public static string FormatChineseNumber(long number)
{
var numberText = new List<string>
{
"零", "壹", "貳", "參", "肆", "伍", "陸", "柒", "捌", "玖"
};
var unitText = new List<string>
{
"", "拾", "佰", "仟"
};
var groupText = new List<string>
{
"", "萬", "億", "兆"
};
var result = number.ToString()
// 反轉
.Reverse()
// 轉中文: 10 -> 壹零
.Select(it => numberText[it - '0'])
// 分組並加上單位: 壹零壹 -> 壹『佰』零壹
.Select((it, i) => new
{
group = i / 4,
text = it + (it == "零" ? "" : unitText[i % 4])
})
// 轉回來
.Reverse()
// 分組處理『億、萬』
.GroupBy(it => it.group)
.Aggregate(((bool prevGroupZero, string text))(false, ""),
(r, it) =>
{
var temp = it
.Aggregate(((bool prevZero, string text))(false, ""),
(rr, itt) =>
{
if (itt.text == "零")
return (true, rr.text);
// 將非零項目加入字串
return (false, rr.text +
(rr.prevZero ? "零" : "") + itt.text);
});
// 處理群組
if (temp.text == "")
return (true, r.text );
// 將非零群組加入字串
return (false, r.text + (r.prevGroupZero &&
!temp.text.StartsWith("零") ? "零" : "") +
temp.text + groupText[it.Key]);
});
return result.text == "" ? "零" : result.text;
}
邏輯有參考 淺水員大 的程式
寫完後覺得順很多,原來處理億萬的地方不太順
units1 = ["", "拾", "百", "千"]
units2 = ["", "萬", "億"]
digitals = ["零", "壹", "貳", "參", "肆", "伍", "陸", "柒", "捌", "玖"]
test1 = 100
test2 = 60058905
test3 = 999999999
def digi2chinese(s):
# 轉換數字成國字,並且補單位(個十百千)
tmp = [
digitals[int(c)] + units1[len(s) -1 - i] if c != "0" \
else digitals[int(c)] \
for i, c in enumerate(s)]
# 合併重複之"零"
tmp2 = ""
for t in tmp:
if tmp2 == "" or tmp2[-1] != "零" or t != "零":
tmp2 += t
# 處理尾部之零
return tmp2[:-1] if tmp2[-1] == "零" else tmp2
def convert2chinese(num):
# 將數字轉換為字串,並將其顛倒
reversedStr = str(num)[::-1]
# 將數字每4個分為一組
tmp = [
reversedStr[i:i+4] if i is not None \
else reversedStr[i:] \
for i in range(0, len(reversedStr), 4)]
# 還原數字,並對其做轉換成正楷和加入單位(個十百千)
tmp = [digi2chinese(t[::-1]) for t in tmp][::-1]
# 補上大單位(萬億)並結合,高興的話還可以擴展
return "".join(t+units2[len(tmp)-1-i] for i, t in enumerate(tmp))
print(convert2chinese(test1))
print(convert2chinese(test2))
print(convert2chinese(test3))
應該你愛擴充到多少位都可以
改進一些寫法,弄簡潔一點並補註解。
然後看了一下上面的,解法差不多嘛。哈
對於零的處理,如果依照國小教的念法,下列提供幾筆測試資料
20,1000,0000 => 二十億一千萬
20,0100,0000 => 二十億零一百萬
20,0000,1000 => 二十億零一千
20,0000,0100 => 二十億零一百
下面是 javascript 版本的程式碼
(沒用特殊的功能,應該很容易轉換成其他語言)
function toChineseNumber(s) {
const uintA = ['', '萬', '億', '兆'],
unitB = ['', '拾', '佰', '仟'],
unitC = ['零', '壹', '貳', '參', '肆', '伍', '陸', '柒', '捌', '玖'];
let outStr = '', //儲存輸出字串
i = (s.length - 1) >>> 2, //uintA 的 index
j = (s.length - 1) & 3, //unitB 的 index
k = 0, //讀取 s 的 index
zero = false, //前面是不是有零
emptyBlock = true; //對於 uintA 區間,是不是四個位數都是零
for (; i >= 0; --i) {
for (; j >= 0; --j) {
let x = parseInt(s[k++], 10);
if (x === 0) {
zero = true;
} else {
outStr += (zero ? '零' : '') + unitC[x] + unitB[j];
zero = false;
emptyBlock = false;
}
}
j = 3;
if (!emptyBlock) {
outStr += uintA[i];
emptyBlock = true;
zero = false;
}
}
return outStr;
}
有興趣可試試linqjs
雖然我沒玩過