用javascript实现数字大小写转换

需求:

大小写互转

小写

大写

金融大写

0

123

一百二十三

103

一百零三

1003

一千零三

ok,我们先来研究一下

小写

小写长度

常用大写

大写长度

完整大写

完整大写长度

0

0

=

=

=

123

3

一百二十三

=

=

=

103

3

一百零三

=

一百零十三

5

1003

4

一千零三

4

一千零百零十三

7

上面的数字比较短,这里就来个更长的数字

零亿零千零百零十零万零千零百零十零亿零千零百零十零万零千零百零十零亿零千零百零十零万零千零百零十零

上面用的大写形式,好看点,其实就是下面三段,这个数字够大了

亿零千零百零十零 万零千零百零十零

亿零千零百零十零 万零千零百零十零

亿零千零百零十零 万零千零百零十零

1

9 8765 4321

9 8765 4321

9 8765 4321

这里我们可以发现好几个规律性的东东

1. 除了个位上的数没有单位外,其它位上的数字都有单位,其实也有就是个,但是一般不用

2. 数字的单位有,个十百千万亿,常用的就这些,其它自己去研究

3. 数字的长度和其完整大写长度的关系为,数字.len*2-1=完整大写.len

4. 每5位是一个万的循环, 每9位是一个亿的循环(小写形式看出)

5. 小写可以转成完整大写,只需要在相应位上加上单位

6. 完整大写可以转成常用大写,只需要省略掉零位及其单位

7. 小写和常用大写没有直接规律,但是小写和完整大写,常用大写和完整大写有规律

8. 小写->完整大写->常用大写,就是一个完整过程

-------------------------------小写转大写

已经很清楚小写转大写的完整过程了,ok下面上代码

单位数组

UNIT:["千","","十","百","万","亿"]

大写数字数组

UNUM:["零","一","二","三","四","五","六","七","八","九"]

为了处理方便,我们总是倒序处理大小写,所以先来个反转函数

1  function Reserve(S)     {
2      //return S.split("").reverse().join("");
3      var tmp="";
4       for(i=;i<S.length;i++){
5          tmp=S.charAt(i)+tmp;
6      }
7       return tmp;
8  }

第一步:将小写数字转成完整大写形式,假设n是数字的字符串形式

 1  function ToFullUpper(n)
 2  {
 3      var S=Reserve(n);
 4      var R="";
 5      for (i=0;Len=S.length,i<Len;i++)
 6      {
 7          //如果是第9位的倍数,这么这个一定是亿位
 8          if (i%8==0  && i!=0 )
 9             R=this.UNUM[S.charAt(i)]+this.UNIT[5]+R
10          //如果是第5位的倍数,这么这个一定是万位
11          else if (i%4==0 && i!=0)
12              R=this.UNUM[S.charAt(i)]+this.UNIT[4]+R
13          //其它位则对应 个十百千,请注意个位的特殊处理方式
14          else
15              R=this.UNUM[S.charAt(i)]+this.UNIT[(i+1)%4]+R
16      }
17      return R;
18  }

现在R就是n对应的完整大写字符串了

第二步,将R中的零位都去除掉

 1 function TrimZero(R)
 2 {
 3     return R.replace(/零([十百千])/ig,"零")  
 4     .replace(/亿零{4,4}万/ig,"亿")
 5     .replace(/([亿万])零{4,4}/ig,"$1")
 6     .replace(/零{2,3}/ig,"零")
 7     .replace(/([十百千])零{1,3}([万|亿])/ig,"$1$2")
 8     .replace(/(.*)零$/,"$1")
 9     .replace(/零亿/ig,"零")
10     .replace(/^一十/,"十");
11 }

这里除零函数不知道是不是有问题,如果有简单的写法,请告诉我

replace(/零([十百千])/ig,"零")

10001

一万零千零百零十一

一万零零零一

replace(/亿零{4,4}万/ig,"亿")

1 0000 0001

一亿零千零百零十零万零千零百零十一

经过第一步

一亿零零零零万零零零一

一亿零零零一

replace(/([亿万])零{4,4}/ig,"$1")

replace(/零{2,3}/ig,"零")

一千零零一

一万零零零一

一千零一

一万零一

replace(/([十百千])零{1,3}([万|亿])/ig,"$1$2")

replace(/(.*)零$/,"$1")

去掉末尾的零

replace(/零亿/ig,"零")

replace(/^一十/,"十");

一十

最终数字转大写函数

1 function ToUpper(s)
2 {
3     return TrimZero(ToFullUpper(s));
4 }

至此,小写转大写结束

-------------------------------大写转小写

同样的规律

常用大写->完整大写->小写

这里有个问题,完整大写需要一个模板来作为参照物,类似于Format格式

幸运的是我们已经有了

零亿零千零百零十零万零千零百零十零亿零千零百零十零万零千零百零十零亿零千零百零十零万零千零百零十零

无论完整大写是什么,都只是上面的子集

请注意对比下面四组数据,全部是倒序

模板

零十零百零千零万零十零百零千零亿零十零百零千零万零十零百零千零亿零

常用(原始)

一零百五千三万四十二零千一

完整

零百五千三万四十二零千一

常用(缺)

一 零百五千三万四十二 零千一

  1. 对比模板常用(原始)两组数据,现在将常用(原始)的每一位填入模板中,然后去掉,模板多余的位,得到完整形式
  2. 完整和常用(原始)对比,可以发现常用(缺)缺少只是空格标出的地方
  3. 如果换成其它更多形式对比,最终发现,只是缺少单位和零
  4. 通过常用和模板的对比可以得出完整形式

第一步,按照完整大写模板,将常用大写转成完整大写,循环原始数据,如果缺少在模板中对应的位或者单位就补进去.

 1 function ToLower (ms)
 2 {
 3    //全零数
 4 
 5    if (ms.replace(/零*/ig,"")=="") return "0";
 6    var fmt="零亿零千零百零十零万零千零百零十零亿零千零百零十零万零千零百零十零亿零千零百零十零万零千零百零十零";
 7    var mod="零一二三四五六七八九"
 8   if (ms=="十") ms="十零"
 9   if (ms.charAt(0)=="十") ms="一"+ms
10 
11    fmt=Reserve(fmt);
12    ms=Reserve(ms);
13 
14    var result=""
15    var n=0;
16 
17    for(i=0;i<ms.length;i++)
18    {
19          var cc=ms.charAt(i);
20         //如果是1-9直接拷贝
21          if (mod.indexOf(cc)>-1 && cc!="零")
22          {
23               result+=cc;
24               n++;
25          }//碰到单位的时候,从模板中n开始拷贝到单位位置
26          else if (mod.indexOf(cc)<0)
27          {
28               var a=fmt.indexOf(cc,n);
29               result+=fmt.substr(n,a-n+1);
30               n+=a-n+1;
31          }//由于在单位中处理拷贝过零,这里不需要再处理了
32          else  (cc=="零")
33          {
34               continue;
35          }
36    }
37    //将单位都去掉
38    result=Reserve(result).replace(/[亿万千百十]/ig,"");
39    //用数字字符替换大写字符
40    for(i=0;i<this.UNUM.length;i++)
41    {
42          while(result.indexOf(this.UNUM[i])>-1)
43               result=result.replace(this.UNUM[i],i);
44    }
45    return result;
46 }

关于fmt的问题,fmt决定了此函数最长能转换多大的数字,一般万亿的就足够了,也可以自己动态生成一个

可以弄成常量,速度更快点,自己看着办

-------------------------测试

由于数字有十个,分成两组0,1-9,0比较特殊,1-9是等价的,所以测试数据只需要0和1的组合,也就是可以用二进制来产生测试数据

 1 function Generate (s)
 2 {
 3     if (s.replace(/[0-1]*/ig,"")!="") return"";
 4     if (s.replace(/1*/ig,"")=="") return "1"+s.replace(/1/ig,"0");
 5     var arr=new Array;
 6     for(i=0;i<s.length;i++)
 7         arr[i]=s.charAt(i);
 8 
 9     for(i=0;i<s.length;i++)
10     {
11           if (arr[s.length-i-1]=='1')
12                 arr[s.length-i-1]='0'
13           else
14           {
15                 arr[s.length-i-1]='1';
16                 break;
17           }
18     }
19     return arr.toString().replace(/,/ig,"");
20 }

测试代码

 1 function test (){
 2     var s="0"
 3     //由于是二进制方式产生数据 所以10250可以产生10250行数据
 4     最后一个是 十万一千亿一千零一十
 5     for (ii=0;ii<10250;ii++)
 6     {
 7         //测试数据
 8         s=Generate(s);
 9         //小写转大写
10         upper=ToUpper(s);
11         //大写转小写
12         low=ToLower(upper);
13      //document.writeln((s==low)+ "\t\t"+s+"\t\t"+low+"\t\t"+upper)
14     }
15 }

---------------

如果要实现金融大小写转换,只需要把大写形式变成金融大写就搞定了