[閒聊] 中文數字轉阿拉伯數字

作者: laechan (揮淚斬馬雲)   2021-11-15 09:53:55
最近有人問,思考了一下做法,以下是偏懶人做法,例如各 mud
大致都有 chinese_number 這個 simul_efun,比方:
int n=12345;
string sn=chinese_number(n);
write(n+" = "+sn);
結果
12345 = 一萬兩千三百四十五
那問題就是如何把 一萬兩千三百四十五 轉回 12345,簡單的做
法是土法煉鋼:
int return_n(string sn)
{
int i=0;
while(i++>=0)
if(sn==chinese_number(i))
return i;
}
但是這樣的問題就是無效的呼叫太多,而且數字越大,迴圈越久
,這時直覺的想法就是做個簡單的區別,例如假設整數最大數值
是 21 億多:
int return_n(string sn)
{
mixed tmps=({});
int n=0;
if(strsrch(sn,"億"))
{
tmps=explode(sn,"億");
if(sizeof(tmps)<2) tmps+=({"零"});
for(i=1;i<10000;i++)
if(tmps[0]==chinese_number(i))
break;
n+=i*100000000;
sn=tmps[1];
}
if(strsrch(sn,"萬"))
{
tmps=explode(sn,"萬");
if(sizeof(tmps)<2) tmps+=({"零"});
for(i=0;i<10000;i++)
if(tmps[0]==chinese_number(i))
break;
n+=i*10000;
sn=tmps[1];
}
for(i=0;i<10000;i++)
if(sn==chinese_number(i))
break;
n+=i;
return i;
}
也就是把它拆成看多少個億、然後底下多少個萬、再底下有多少,
去各自做解析,這樣迴圈可以跑少一點。
進一步來說,針對多少個億、多少個萬、..,還可以做以下的解析
int return ranges(string tmp_sn)
{
if(strsrch(tmp_sn,"千"))
return ({1000,10000});
else if(strsrch(tmp_sn,"百"))
return ({100,1000});
else
return ({0,100});
}
然後上面的 return_n 函數內部份做改寫如下:
mixed ranges=({});
if(strsrch(sn,"萬"))
{
tmps=explode(sn,"萬");
if(sizeof(tmps)<2) tmps+=({"零"});
ranges=return_ranges(tmps[0]);
for(i=ranges[0];i<ranges[1];i++)
if(tmps[0]==chinese_number(i))
break;
n+=i*10000;
sn=tmps[1];
}
它的意思是:
如果是一千兩百三十四,那 for(i=1000;i<10000;i++) 就好
如果是一百二十三,那 for(i=100;i<1000;i++) 就好
如果是五十九,那 for(i=0;i<100;i++) 就好
根據以上,還可以進一步改寫 return_ranges 函數:
int return ranges(string tmp_sn)
{
int t;
if(t=strsrch(tmp_sn,"千"))
{
switch(tmp_sn[t-2..t-1])
{
case "一": return ({1000,2000}); break;
case "二":
case "兩": return ({2000,3000}); break;
case "三": return ({3000,4000}); break;
.
.
case "九": return ({9000,10000}); break;
}
}
上面的判斷也可以寫成函數比方 return_units
int return_units(string tmp_unit)
{
switch(tmp_unit)
{
case "一": return ({1000,2000}); break;
case "二":
case "兩": return ({2000,3000}); break; // 留意 2 會有二跟兩
case "三": return ({3000,4000}); break;
.
.
case "九": return ({9000,10000}); break;
}
}
這樣 return_ranges 就可以改寫為
int return ranges(string tmp_sn)
{
int t;
if(t=strsrch(tmp_sn,"千"))
return return_units(tmp_sn[t-2,t-1]);
else if(t=strsrch(tmp_sn,"百"))
return return_units(tmp_sn[t-2,t-1]);
// 百以下就不管了 for(i=0;i<100; 迴圈數不多)
else
return ({0,100});
}
比方
如果是三千兩百二十一,那就 for(i=3000;i<4000;i++)
那可不可以再進一步解析讓迴圈少跑一點呢? 可以,但是,沒必要,
我一慣的想法是:
把解析寫得很簡單 => 程式跑起來loading大
把解析寫得很複雜 => 程式跑起來loading小
那根據均值定理,必定存在一種寫法,可以取得平衡,即程式解析不
用寫得很精確,程式跑起來loading也不會太重就好了。
(上面的程式及函數段,我沒有實際跑過,可能會有 error 要 debug)
以上,一點分享。前提是中文數字的產生均是透過 chinese_number
,例如說如果你要程式解析 "玖壹壹",這是辦不到的,因為通常在
mud 裡頭不會把 int n=911 解成 "玖壹壹",而會解成"九百一十一"
Laechan
作者: tsetsethatha (吉星麥造~~~我來了)   2021-11-16 22:17:00
感謝分享!!

Links booklink

Contact Us: admin [ a t ] ucptt.com