LuoJun_LZ 发表于 2009-11-22 01:17:05

用C写个中文数字转换函数

如题,函数形式为:
long Num(char str[]){...}
要求能实现如下转换:
"千">>1000
"五一二">>512
"二百三十">>230
"九十万">>900000
"十亿二百万零廿三">>1002000023
"万万">>100000000

大家来出出主意.
5L代码文曲星用,函数形式为long numch(int pt);
7L代码C用,函数形式为double numch(char *str);

[ 本帖最后由 LuoJun_LZ 于 2009-12-24 17:04 编辑 ]

FantasyDR 发表于 2009-11-22 21:40:48

"五一二">>512
"二百三十">>230

仅两个就无法区分啊。你这个要求给得太模糊了。

LuoJun_LZ 发表于 2009-11-23 00:02:04

这两个可以区分呀.
"五一二"中没有表示位数的文字,可用循环实现以下式子:
512=((5*10)+1)*10+2;
而"二百三十"中有两个表示位数的文字~~计算方式变为:
230=2*100+3*10
两种算法综合后,可把:
如"三五百一十"转为:3510

FantasyDR 发表于 2009-11-23 12:59:54

汗……原来是中文转阿拉伯数字啊。
我还以为是阿拉伯数字转中文=_=

LuoJun_LZ 发表于 2009-11-23 17:49:12

汗,从函数形式就能看出来了呀~ 不过也可以弄个数字转中文的

LuoJun_LZ 发表于 2009-12-11 21:48:12

:L 汗,都没什么人回应~~

我在文曲星上用LAV1写了一个,分享下:
char _NUMBER[]="零一壹二贰三叁四肆五伍六陆七柒八捌九玖十拾廿百佰千仟万兆亿";

long _Num(int pt1,int pt2,char len)//各位数字,位,位数
{//递归辅助函数
long tmp, i, a, btmp;
int w;//位数指针
char c;//指针
char k;
char t;
char tt;

w = len - 1;
while(w>=0)//逆序检测顺序是否由大到小
{
if(*(pt2+w-1)<=*(pt2+w))
{
   c = w;
   while(*(pt2+w-1)<=*(pt2+c) && w)
    w--;
   len = len - c + w;

   memcpy(&tmp,pt1+c*4,4);//取升位数
   memcpy(t,pt1+4+c*4,60-c*4);//移动
   memcpy(tt,pt2+c,15-c);//移动
   tmp = _Num(pt1+w*4,pt2+w,c-w)+tmp;//递归赋值
   memcpy(pt1+w*4,&tmp,4);
   memcpy(pt1+4+w*4,t,60-c*4);//移动
   memcpy(pt2+w,tt,15-c);//移动
}
w--;
}

a = 0;
c = 0;
while(c<len)//计算
{
memcpy(&tmp,pt1+c*4,4);
k = *(pt2+c);
if(10 == k)
   i = 10;
else
   if(11 == k)
    i = 20;
else
   if(12 == k)
    i = 100;
else
   if(13 == k)
    i = 1000;
else
   if(14 == k)
    i = 10000;
else
   if(15 == k)
    i = 1000000;
else
   if(16 == k)
    i = 100000000;
else
   i = 1;

if(tmp)
   a = a + i*tmp;
else
   if(k)
    a = a + i;
c++;
}
return a;
}
long numch(int pt)
{//转成非负整数
char x,k;
char w, len;
int b;
long num;

memset(num,0,64);
memset(w,0,16);

b = pt;
len = 0;
k = 1;

while(len<16 && *b)//循环1,取得数字代号
{
if(*b<128)
{
   x = *b-'0';
   if(x > 9)
    break;
   b--;
}
else
{
   memcpy(&nc,b,2);
   x = 0;
   while(x<29 && (*b != _NUMBER || *(b+1) != _NUMBER))x++;//取得实际数字
   if(x==29)
    break;//遇到非数字字符
   if(x<21)
    x = x+1>>1;
   else if(x==21)
    x = 11;
   else if(x<26)
    x = x + 2 >>1;
   else x = x - 12;
}
if(x>=10)
{
   *(w+len)=x;
   len++;
   k = 1;
}
else
{
   if(!x)
    k = 0;
   num = 10*num+x;//记录
}
b = 2 + b;
while(*b==' ')b++;//消除空格
if(*b ==',')b++;//遇到一个逗号
}
if(b == pt)
return -1;//出错
if(!len)//普通类型转换
return num;
if(num)
{
if(k)
   if(!w)//处理如“二百五”=250的情况
    if(w>12)
   w = w-1;
    else
   if(w==12)
      w = 10;
len ++;
}
return _Num(num,w,len);
}

//支持类型如:(实现中文大小写和阿拉伯数字混合使用)
//"1,000,000"=1000000;
//"1 2 3 45"=12345
//"一三五"=135
//"1百3十"=130;
//"五拾叁万"=530000
//"贰佰5"=250
//"贰佰05"=205
//"百万"=1000000

[ 本帖最后由 LuoJun_LZ 于 2009-12-22 16:24 编辑 ]

juyan 发表于 2009-12-13 20:56:21

好样的。好久没人在WQX上写什么程序了

LuoJun_LZ 发表于 2009-12-16 21:48:30

其实这个函数速度较慢,
文曲星上转换“一十九亿九千九百九十九万九千九百九十九”=1999999999
要0.26秒

又用C写了个,几乎完全注释:

#define MAX 16 //最大位数

char _NUMBER="零一壹二贰三叁四肆五伍六陆七柒八捌九玖十拾廿百佰千仟万兆亿";

double _Num(double *num,char *wei,char len)//各位对应数字,位,位数
{//递归辅助函数
      double i, a, tmp;//临时数字
      int w;//位数指针
      char c;//指针

      w = len - 1;

      while(w>0)//逆序检测单位顺序是否由大到小,如“五千万五千”的单位顺序就不是由大到小
      {
            if(*(wei+w-1) <= *(wei+w))//前一个单位小于或等于后一个单位
            {
                  c = w;//记录后一单位
                  w--;

                  while(*(wei+w-1)<=*(wei+c) && w)//检索到前一个单位大于记录单位为止
                        w--;

                  *(num+w) = _Num(num+w,wei+w,c-w) + *(num+c);//递归赋值

                  len = len - c + w;//长度收缩

                  for(char x=w+1;x<len;x++)//合并各位对应数值
                        *(num+x) = *(num+x+c-w);

                  for(x=w;x<len;x++)//合并位
                        *(wei+x) = *(wei+x+c-w);
            }
            w--;
      }
      a = 0;//临时计算用数
      c = 0;
      while(c<len)//计算
      {
            tmp = *(num+c);
            switch(*(wei+c))
            {
            case 10: i = 10;break;
            case 11: i = 20;break;
            case 12: i = 100;break;
            case 13: i = 1000;break;
            case 14: i = 10000;break;
            case 15: i = 1000000;break;
            case 16: i = 100000000;break;
            default : i = 1;
            }
            if(tmp)
                  a = a + i*tmp;
            else
                  if(*(wei+c))
                        a = a + i;//将单位转换为数值
            c++;
      }
      return a;
}

double numch(char *str)
{//转成非负整数
      char wei={0};//位数记录
      char len=0;//下标最大值
      double num={0};
      char x,k;//临时数据
      char *t = str;//临时指针

      while(len<MAX && *t)//循环,筛选整理
      {
            if(*t<='9' && *t>='0')//若是阿拉伯数字字符
            {
                  x = *t - '0';//计算
                  t--;//阿拉伯数字只占一个字节
            }
            else
            {
                  x = 0;
                  while(x<29 && (*t != *(_NUMBER+x*2) || *(t+1) != *(_NUMBER+x*2+1)))
                        x++;//检测比较中文字符

                  if(x==29)
                        break;//遇到非数字字符

                  if(x<21)
                        x = (x + 1) / 2;//0~9、十,代号10
                  else if(x==21)
                        x = 11;//廿,代号11
                  else if(x<26)
                        x = (x + 2) / 2;//百、千,代号12、13
                  else
                        x = x - 12;//万、兆、亿,代号14、15、16
            }
            if(x>=10)//遇到位代号记录位
            {
                  *(wei+len)=x;//直接使用10~16作代号
                  len++;
                  k = 1;//k==1时关注如“二百五”==250的情况
            }
            else//遇到数字记录数字
            {
                  if(!x)
                        k = 0;//遇到数字为0取消对“二百五”情况的关注
                  *(num+len) = *(num+len) * 10 + x;//每个位对应数字可以大于10
            }

            t += 2;//每个汉字占两个字节(阿拉伯数字已预先减1)
            while(*t==' ')//其他处理,消除空格
                  t++;
            if(*t ==',')//其他处理,遇到一个逗号
                  t++;
      }

      if(t == str)
            return -1;//第一字符非数字字符

      if(!len)//无单位类型返回
            return num;

      if(num)//不以0结尾
      {
            if(k)//关注“二百五”类型
                  if(!wei)//不以非“个”单位结尾
                  {
                        if(wei>12)//“千”及以上单位
                              *(wei+len) = *(wei+len-1) - 1;//单位降1
                        else
                              if(*(wei+len-1) == 12)//单位“百”降一位是“十”,11是“廿”的代号
                                    *(wei+len) = 10;
                  }
            len ++;//凡不以0结尾,计算位数要加1
      }

      return _Num(num,wei,len);//进入递归环节
}

//下面验证一下:
#include "stdio.h"
void main()
{
      printf("一二三四五六七八九十>>%.0f\n",numch("一二三四五六七八九十"));
      printf("壹贰叁肆伍陆柒捌玖拾>>%.0f\n",numch("壹贰叁肆伍陆柒捌玖拾"));
      printf("1,2 3,4 5,6 7,8 9,0 >>%.0f\n",numch("1,2 3,4 5,6 7,8 9,0 "));
      printf("一贰三肆五陆七捌九拾>>%.0f\n",numch("一贰三肆五陆七捌九拾"));
      printf("1 贰3,肆 5陆,7捌 9拾>>%.0f\n",numch("1 贰3,肆 5陆,7捌 9拾"));
      printf("5十万3百>>%.0f\n",numch("5十万3百"));
      printf("1 六>>%.0f\n",numch("1 六"));
      printf("1,000>>%.0f\n",numch("1,000"));
      printf("一>>%.0f\n",numch("一"));
      printf("贰>>%.0f\n",numch("贰"));
      printf("百>>%.0f\n",numch("百"));
      printf("十万>>%.0f\n",numch("十万"));
      printf("九亿五百万肆千>>%.0f\n",numch("九亿五百万肆千"));
      printf("2兆廿一>>%.0f\n",numch("2兆廿一"));
      printf("2佰伍>>%.0f\n",numch("2佰伍"));
      printf("2佰0伍>>%.0f\n",numch("2佰0伍"));

      while(getchar()!='\n');
}

[ 本帖最后由 LuoJun_LZ 于 2009-12-24 17:06 编辑 ]
页: [1]
查看完整版本: 用C写个中文数字转换函数