Fw: [闲聊] 中文数字转阿拉伯数字

楼主: laechan (挥泪斩马云)   2021-11-15 09:54:06
※ [本文转录自 mud 看板 #1XaRstnC ]
作者: laechan (挥泪斩马云) 看板: mud
标题: [闲聊] 中文数字转阿拉伯数字
时间: Mon Nov 15 09:53:55 2021
最近有人问,思考了一下做法,以下是偏懒人做法,例如各 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

Links booklink

Contact Us: admin [ a t ] ucptt.com