java实战1——浮点数转人民币读法

来源:互联网 发布:淘宝c店保证金 编辑:程序博客网 时间:2024/06/06 05:47
为了学习安卓,现在开始从C++角度来学习Java,现在看到了《疯狂java讲义》的第四章,里面有个字符串转人民币的例子,书上没做完,于是把其补充完善。其中最难的部分就是根据零在不同位置,具有不同行为。按照中文读法,有些零要读出,有些零不需要读出。下面将按照两部分进行讲解,首先举一个例子来说明思路,其次给出Java的源代码供参考,并且进行测试。这个问题主要利用字符串数组来解决。我们假定要转换的浮点数整数部分不超过12位。

(1) 思路


1.1 分割整数和小数部分

       对于一个浮点数,先来看个简单点,不加零。比如12312341234.12。按照中文人民币的读法,四位一读,所以其应该读做“一百二十三亿一千二百三十四万一千二百三十四元一角二分”。首先将浮点数分为两个部分,整数部分(IntPart)和小数(FloatPart)部分。如何分割呢?就是将该浮点数直接强制取整得到整数部分,如: IntPart =(int)12312341234.12=12312341234,然后用原浮点数减去整数部分后再乘以100(因为中文读法最多为角分,为两位),再进行强制转为整数。这样就得到了小数部分。如 12312341234.12-IntPart = 0.12,FloatPart =(int)(0.12*100) = 12。然后分别将小数部分(这时也是个整形)和整形部分在将其变为字符串,然后进行第二步,处理整数部分读法和小数部分读法。

1.2   整数部分转中文字符串

     前面已经将浮点数分割为两个部分了,首先先处理整数部分转中文字符串。将字符串逐一变为汉字,首先要建立一个汉字库(利用数组实现)。可以这样 String[] ChineseArr ={“零”,”一”,”二”…}

      然后通过逐一扫描整数字符串,将其映射到汉字数组中,也就是利用每个数字本身的算术值,进行索引数组,做映射。比如 1.其数字为1,那么就映射到汉字数组中ChineseArr[1]正好就是汉字“一“。然后将其加入到结果字符串中。对于单位的处理,也是利用一个单位数组来进行映射。String[] UnitArr ={“千”,”百”,”十”}。个位不需要单位。如何确保单位的正确匹配呢?这里就要按照整数部分 4位一划分:123 1234 1234。这样就分为3个部分,然后在逐一处理每个部分,每个部分的处理都可以抽象出来,写成一个子函数,这个函数专门用来处理4位数字变成汉字。比如123 1234 1234将其分为3个部分,”123“,”1234“,”1234“,然后分别调用同一个方法后,再进行扫尾处理。

      比如“1234“如何变为汉字串呢?首先逐一扫描字符串,将该字符变为数字,然后映射到汉子数组和单位数组中。

下面为该函数的完整的实现:

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public String NumStr2ChineseStr_IntPartCore(String NumStr)  
  2.     {  
  3.         String rst = ""//保存结果 初始化为空  
  4.         int len = NumStr.length(); //获取NumStr的长度  
  5.           
  6.         //补零操作  
  7.         if(len < 4//位数小于4位就前补位  
  8.         {  
  9.             String[] AddZeroStr = {"0","00","000"};  
  10.             NumStr = AddZeroStr[4-len-1] + NumStr;  
  11.         }  
  12.         len = NumStr.length(); //更新长度 其实 len==4  
  13.           
  14.         //扫描至第一个不为0的字符  
  15.         int i=0;   
  16.         while(i < len && NumStr.charAt(i)-'0'==0)  
  17.                     ++i;  
  18.                       
  19.         if(i==len) //四个数都为零 ,就直接输出一个零 并返回  
  20.         {  
  21.             rst += "零";  
  22.             return rst;  
  23.         }  
  24.         //四个数不都为0的情况  
  25.         for(;i < len; ++i)  
  26.         {  
  27.             int num = NumStr.charAt(i) - '0';  
  28.             if( i != len-1 && num != 0)//不是末尾且不为0  
  29.             {  
  30.                 rst += ChineseArr[num] + UnitArr[i] ;//直接映射汉字和单位  
  31.             }  
  32.             else  
  33.             {     
  34.                 //若当前结果字符串中最后一位不是“零”,且数字串最后一位不是数字0 这样对中间2个零的只添加一个“零”如1003  
  35.                 if( rst.length()>0 && rst.charAt(rst.length()-1) != '零' && NumStr.charAt(len-1)-'0'!= 0)  
  36.                 { //四位中第二,三位至少有一个为0且最后一位数字不为0 如1003 则为一千零三  
  37.                     if((i==1||i==2) && num == 0)  
  38.                         rst += "零";  
  39.                 }  
  40.                 if( i== len - 1 && num !=0)//是最后一位,且数字不为0 不加单位  
  41.                 {  
  42.                     rst += ChineseArr[num];  
  43.                 }  
  44.             }  
  45.         }  
  46.             return  rst; //返回结果字符串   
  47.     }  

     现在分析上述代码,该函数只处理4位的数字串,不足四位的补为4位进行处理。"1234","123",1023","1002","1000",”123”,”3”经过该函数后依次为“一千二百三十四”,"一百二十三",“一千零二十三”,“一千零二”,“一千“,”一百二十三”,”三”。该函数的主要功能是将4位的数字串变为汉字串,函数从第一位不是0的字符开始扫描并映射,由于数字串最末位不单位,所以将4位的数字串分为两部分,前3位加单位,最后一位不加单位。而对于汉字的读法,对于4位数字串中中间两位可能为0的情况,又要加“零”。比如前面的例子中,“1002”,“1023”都读法中要加“零”。

        所以将前3位处理的第一部分中,进行0的处理。详细实现见代码注释。但是通过该函数,只能将数字字符串化为可读的汉字串,而对于多部分的4位连接情况中的零则没有完成,比如一个数字串的整数部分为“12301230123”,则分解3部分后,“123”,“0123”,“0123”,在逐一经过上述函数后,变为“一百二十三”,“一百二十三“,”一百二十三“。必须在链接过程中,进行”亿“,”“万”,“元”单位的连接和零的连接。上述例子:最后应读成“一百二十三亿零一百二十三万零一百二十三元”。整数部分完整处理代码如下。

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. /*将12位整数部分数字转为汉字字符串 
  2.      */  
  3.     public String NumStr2ChineseStr_IntPart(String NumStr)  
  4.     {  
  5.         int len = NumStr.length(); //获取字符串总长度  
  6.         int partNum = (len%4==0) ? (len/4) : (len/4)+1;//将12位内数字分为几部分  
  7.         String Str_yi="",Str_wan="",Str_yuan=""//分别定义亿,万,元字符串  
  8.         String FirstStr,SecondStr,ThirdStr; //12位内至多分为三部分  
  9.         int tmp_len; //用于计算临时有效字符串长度 (去除0)  
  10.         boolean FourValidBit_yuan = false ; //判断第三部分是否为4位  
  11.         switch(partNum)  
  12.         {  
  13.             case 1//只有1部分,就是xxx元  
  14.             {  
  15.                 Str_yuan += NumStr2ChineseStr_IntPartCore(NumStr);  
  16.                 break;  
  17.             }  
  18.             case 2//有2部分,就是 xxx万xxx元  
  19.             {//注意 String.substring(beginindex,endindex)中endindex不包含  
  20.                 int endindex = len - 4 ;  
  21.                 FirstStr = NumStr.substring(0,endindex);  
  22.                 Str_wan += NumStr2ChineseStr_IntPartCore(FirstStr)+"万";  
  23.                 SecondStr = NumStr.substring(endindex,len);  
  24.                 Str_yuan += NumStr2ChineseStr_IntPartCore(SecondStr);  
  25.                 tmp_len = GetVaildStrLen(SecondStr);  
  26.                 if(0 <tmp_len && tmp_len < 4 )  
  27.                         Str_yuan = "零"+ Str_yuan;  
  28.                 break;  
  29.             }  
  30.             case 3://有3部分,就是 xxx亿xxx万xxx元  
  31.             {  
  32.                 int endindex2 = len - 4;   
  33.                 int endindex1 = endindex2 - 4;  
  34.                 FirstStr = NumStr.substring(0,endindex1);  
  35.                 Str_yi +=  NumStr2ChineseStr_IntPartCore(FirstStr)+"亿";  
  36.                 SecondStr = NumStr.substring(endindex1,endindex2);  
  37.                 Str_wan += NumStr2ChineseStr_IntPartCore(SecondStr)+"万";  
  38.                 tmp_len = GetVaildStrLen(SecondStr);  
  39.                 if(0< tmp_len && tmp_len<4 ) //中间过程进行补零  
  40.                         Str_wan = "零"+Str_wan;  
  41.                 ThirdStr = NumStr.substring(endindex2,len);  
  42.                 Str_yuan += NumStr2ChineseStr_IntPartCore(ThirdStr) ;  
  43.                 tmp_len = GetVaildStrLen(ThirdStr);  
  44.                 if(0 <tmp_len && tmp_len < 4 )  
  45.                         Str_yuan = "零"+ Str_yuan;  
  46.                 else   
  47.                 {  
  48.                     if( tmp_len == 4)  
  49.                         FourValidBit_yuan  = true;  
  50.                 }  
  51.                 break;  
  52.             }  
  53.         }  
  54.         //对结果进行判断,如果万位和元位都为0 ,  
  55.         if(Str_wan.equals("零万")) //java中时不能直接比较 Str_wan =="零"  
  56.         {  
  57.             if(FourValidBit_yuan )//Str_wan为"零万"且元部分为4位。如12300001234中间需读出"零"  
  58.                     Str_wan = "零";  
  59.             else //否则就不添加   
  60.                     Str_wan = "";   
  61.         }  
  62.         if( Str_yuan.equals("零"))  
  63.             Str_yuan = "";  
  64.         return Str_yi+Str_wan+Str_yuan+"元";  
  65.     }  

     分析:该函数将整数部分分为3段分别处理并且加上单位(亿,万),然后最后通过三个结果串的链接处理,返回结果。关键还是0的处理。在函数中,分别处理后,有一步是计算有效长度的(非0位的个数),来确定是否要添加“零”。比如“12301230123”中间的“0123”在处理完后,就需要加“零”。具体实现间上源码。

1.3 小数部分转中文字符串

       小数部分的实现和整数部分类似,由于小数部分最多有2位。也存在首位是否为0的,是否需要填“零”的问题。具体见下面完整代码实现和注释。

(2)完整实现

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. import java.util.* ;  
  2.   
  3. public class Sample  
  4. {  
  5.     private String[] ChineseArr = new String[]{"零","一","二","三","四","五","六","七","八","九"};  
  6.     private String[] UnitArr = new String[]{"千","百","十"};  
  7.       
  8.     /*四位数的字符串转汉字读法  
  9.      * 如果输入NumStr 不够4位就前补零,变为4位 
  10.      */  
  11.     public String NumStr2ChineseStr_IntPartCore(String NumStr)  
  12.     {  
  13.         String rst = ""//保存结果 初始化为空  
  14.         int len = NumStr.length(); //获取NumStr的长度  
  15.           
  16.         //补零操作  
  17.         if(len < 4//位数小于4位就前补位  
  18.         {  
  19.             String[] AddZeroStr = {"0","00","000"};  
  20.             NumStr = AddZeroStr[4-len-1] + NumStr;  
  21.         }  
  22.         len = NumStr.length(); //更新长度 其实 len==4  
  23.           
  24.         //扫描至第一个不为0的字符  
  25.         int i=0;   
  26.         while(i < len && NumStr.charAt(i)-'0'==0)  
  27.                     ++i;  
  28.                       
  29.         if(i==len) //四个数都为零 ,就直接输出一个零 并返回  
  30.         {  
  31.             rst += "零";  
  32.             return rst;  
  33.         }  
  34.         //四个数不都为0的情况  
  35.         for(;i < len; ++i)  
  36.         {  
  37.             int num = NumStr.charAt(i) - '0';  
  38.             if( i != len-1 && num != 0)//不是末尾且不为0  
  39.             {  
  40.                 rst += ChineseArr[num] + UnitArr[i] ;//直接映射汉字和单位  
  41.             }  
  42.             else  
  43.             {     
  44.                 //若当前结果字符串中最后一位不是“零”,且数字串最后一位不是数字0 这样对中间2个零的只添加一个“零”如1003  
  45.                 if( rst.length()>0 && rst.charAt(rst.length()-1) != '零' && NumStr.charAt(len-1)-'0'!= 0)  
  46.                 { //四位中第二,三位至少有一个为0且最后一位数字不为0 如1003 则为一千零三  
  47.                     if((i==1||i==2) && num == 0)  
  48.                         rst += "零";  
  49.                 }  
  50.                 if( i== len - 1 && num !=0)//是最后一位,且数字不为0 不加单位  
  51.                 {  
  52.                     rst += ChineseArr[num];  
  53.                 }  
  54.             }  
  55.         }  
  56.             return  rst; //返回结果字符串   
  57.     }  
  58.     /* 获取数字字符串的有效位(不是0的位数) 
  59.      */  
  60.     public int GetVaildStrLen(String str)  
  61.     {  
  62.         int start = 0;  
  63.         int len = str.length();  
  64.         while(start < len  && str.charAt(start) =='0')  
  65.             ++ start ;  
  66.         return 4 - start;  
  67.     }  
  68.     /*将12位整数部分数字转为汉字字符串 
  69.      */  
  70.     public String NumStr2ChineseStr_IntPart(String NumStr)  
  71.     {  
  72.         int len = NumStr.length(); //获取字符串总长度  
  73.         int partNum = (len%4==0) ? (len/4) : (len/4)+1;//将12位内数字分为几部分  
  74.         String Str_yi="",Str_wan="",Str_yuan=""//分别定义亿,万,元字符串  
  75.         String FirstStr,SecondStr,ThirdStr; //12位内至多分为三部分  
  76.         int tmp_len; //用于计算临时有效字符串长度 (去除0)  
  77.         boolean FourValidBit_yuan = false ; //判断第三部分是否为4位  
  78.         switch(partNum)  
  79.         {  
  80.             case 1//只有1部分,就是xxx元  
  81.             {  
  82.                 Str_yuan += NumStr2ChineseStr_IntPartCore(NumStr);  
  83.                 break;  
  84.             }  
  85.             case 2//有2部分,就是 xxx万xxx元  
  86.             {//注意 String.substring(beginindex,endindex)中endindex不包含  
  87.                 int endindex = len - 4 ;  
  88.                 FirstStr = NumStr.substring(0,endindex);  
  89.                 Str_wan += NumStr2ChineseStr_IntPartCore(FirstStr)+"万";  
  90.                 SecondStr = NumStr.substring(endindex,len);  
  91.                 Str_yuan += NumStr2ChineseStr_IntPartCore(SecondStr);  
  92.                 tmp_len = GetVaildStrLen(SecondStr);  
  93.                 if(0 <tmp_len && tmp_len < 4 )  
  94.                         Str_yuan = "零"+ Str_yuan;  
  95.                 break;  
  96.             }  
  97.             case 3://有3部分,就是 xxx亿xxx万xxx元  
  98.             {  
  99.                 int endindex2 = len - 4;   
  100.                 int endindex1 = endindex2 - 4;  
  101.                 FirstStr = NumStr.substring(0,endindex1);  
  102.                 Str_yi +=  NumStr2ChineseStr_IntPartCore(FirstStr)+"亿";  
  103.                 SecondStr = NumStr.substring(endindex1,endindex2);  
  104.                 Str_wan += NumStr2ChineseStr_IntPartCore(SecondStr)+"万";  
  105.                 tmp_len = GetVaildStrLen(SecondStr);  
  106.                 if(0< tmp_len && tmp_len<4 ) //中间过程进行补零  
  107.                         Str_wan = "零"+Str_wan;  
  108.                 ThirdStr = NumStr.substring(endindex2,len);  
  109.                 Str_yuan += NumStr2ChineseStr_IntPartCore(ThirdStr) ;  
  110.                 tmp_len = GetVaildStrLen(ThirdStr);  
  111.                 if(0 <tmp_len && tmp_len < 4 )  
  112.                         Str_yuan = "零"+ Str_yuan;  
  113.                 else   
  114.                 {  
  115.                     if( tmp_len == 4)  
  116.                         FourValidBit_yuan  = true;  
  117.                 }  
  118.                 break;  
  119.             }  
  120.         }  
  121.         //对结果进行判断,如果万位和元位都为0 ,  
  122.         if(Str_wan.equals("零万")) //java中时不能直接比较 Str_wan =="零"  
  123.         {  
  124.             if(FourValidBit_yuan )//Str_wan为"零万"且元部分为4位。如12300001234中间需读出"零"  
  125.                     Str_wan = "零";  
  126.             else //否则就不添加   
  127.                     Str_wan = "";   
  128.         }  
  129.         if( Str_yuan.equals("零"))  
  130.             Str_yuan = "";  
  131.         return Str_yi+Str_wan+Str_yuan+"元";  
  132.     }  
  133.     //处理小数字符串部分 最多两位  
  134.     public String NumStr2ChineseStr_FloatPart(String floatStr)  
  135.     {  
  136.         String rst_jiao = "",rst_fen = "";  
  137.         int len  = floatStr.length();  
  138.           
  139.         //补零操作  
  140.         if(len < 2//位数小于2位就前补位  
  141.         {  
  142.             String[] AddZeroStr = {"0","00"};  
  143.             floatStr = AddZeroStr[2-len-1] + floatStr;  
  144.         }  
  145.         for(int i=0 ; i < 2 ; ++i) //2 表示就是两位 因为只有角分而已  
  146.         {  
  147.             int num = floatStr.charAt(i) - '0';  
  148.             if( i == 0)  
  149.             {     
  150.                 rst_jiao += ChineseArr[num] ;  
  151.                 if( num != 0)  
  152.                         rst_jiao += "角";  
  153.             }  
  154.             else  
  155.             {     
  156.                 if(num !=0)  
  157.                         rst_fen += ChineseArr[num]+"分";  
  158.             }  
  159.         }  
  160.         if( rst_fen.equals("") && (rst_jiao.equals("零")||rst_jiao.equals("零角")))  
  161.             rst_jiao = "";  
  162.         return rst_jiao + rst_fen;  
  163.     }  
  164.     /* 将一个有效为15位内的浮点数 变成 人民币中文读法 
  165.      */  
  166.     public String NumStr2ChineseStr(double Num)  
  167.     {  
  168.         long IntPart = (long)Num;   
  169.         long floatPart = Math.round((Num - IntPart)*100);  
  170.         return NumStr2ChineseStr_IntPart(""+IntPart)+ NumStr2ChineseStr_FloatPart(""+floatPart);  
  171.     }  
  172.       
  173.     /* 静态测试方法  
  174.      */  
  175.     public static void Test(String rst, String except)  
  176.     {  
  177.         if(rst.equals(except))  
  178.             System.out.print("test passed\n");  
  179.         else  
  180.             System.out.println("test failed\n");  
  181.     }  
  182.     //入口函数  
  183.     public static void main(String[] args)  
  184.     {  
  185.         Sample SampleOj = new Sample(); //方法要么为静态方法 或者直接创建对象调用其方法  
  186.         //测试第一部分  
  187.         System.out.print("测试1部分:\n");  
  188.         Test(SampleOj.NumStr2ChineseStr(1023.12),"一千零二十三元一角二分");  
  189.         Test(SampleOj.NumStr2ChineseStr(1003.02),"一千零三元零二分");  
  190.         Test(SampleOj.NumStr2ChineseStr(123.3),"一百二十三元三角");  
  191.         Test(SampleOj.NumStr2ChineseStr(123),"一百二十三元");  
  192.         Test(SampleOj.NumStr2ChineseStr(1234),"一千二百三十四元");  
  193.   
  194.         //测试第二部分  
  195.         System.out.print("\n测试2部分:\n");  
  196.         Test(SampleOj.NumStr2ChineseStr(1231234.12),"一百二十三万一千二百三十四元一角二分");  
  197.         Test(SampleOj.NumStr2ChineseStr(1230234.1),"一百二十三万零二百三十四元一角");  
  198.         Test(SampleOj.NumStr2ChineseStr(1230034.02),"一百二十三万零三十四元零二分");  
  199.         Test(SampleOj.NumStr2ChineseStr(1230004),"一百二十三万零四元");  
  200.         Test(SampleOj.NumStr2ChineseStr(1230000.01),"一百二十三万元零一分");  
  201.   
  202.         //测试第三部分  
  203.         System.out.print("\n测试3部分:\n");  
  204.         Test(SampleOj.NumStr2ChineseStr(12312341234.1),"一百二十三亿一千二百三十四万一千二百三十四元一角");  
  205.         Test(SampleOj.NumStr2ChineseStr(12301231234.02),"一百二十三亿零一百二十三万一千二百三十四元零二分");  
  206.         Test(SampleOj.NumStr2ChineseStr(12300230034.02),"一百二十三亿零二十三万零三十四元零二分");  
  207.         Test(SampleOj.NumStr2ChineseStr(12300001234.02),"一百二十三亿零一千二百三十四元零二分");  
  208.         Test(SampleOj.NumStr2ChineseStr(12300000234.12),"一百二十三亿零二百三十四元一角二分");  
  209.         Test(SampleOj.NumStr2ChineseStr(12300000000.02),"一百二十三亿元零二分");  
  210.     }  
  211. }  


总结:首先将数字字符串分为两个部分,整数和小数部分,分开处理,在整数处理部分,又按4位4位来分,先写测试用例分析,哪些地方需要加零,先实现基本功能,在从特殊测试用例角度打补丁。

0 0
原创粉丝点击