黑色硅胶:将数字转为中文金额的大写方式(Java版)

来源:百度文库 编辑:九乡新闻网 时间:2024/04/30 23:18:45
  1. /** 
  2.  * 程序目的: 
  3.  *   从命令行接收一个数,并将其转化为中文金额的大写方式 
  4.  * 例如 123.45 --> 壹佰贰拾叁元肆角伍分 
  5.  * @author LovinChan 
  6.  * 
  7.  *   看到网上有很多这样的例子程序,不过觉得很不满意。有些程序我从命名上就觉得 
  8.  * 实在是不符合规范,程序里面的算法没有让人明白得很清楚的注释,读上去觉得有 
  9.  * 点难度,可读性不强。而且很多程序还存在不少bug,随便一测就测出来了。 
  10.  *   所以本人还是决定重新写一下这个程序,并且尽量做到消除不必要的bug。这个程 
  11.  * 序我没有用什么很精妙的算法,不过用了一些Java类库中的类,像是正则表达式之类 
  12.  * 的东西。由于本人对算法不怎么在行,在做转换操作的时候用的是很笨的方法。望各位 
  13.  * 大虾海涵,呵呵。 
  14.  *  
  15.  *   程序的注释我尽量写得详细一点,如果觉得这个程序哪里有问题或者是哪里有改进的 
  16.  * 地方欢迎随时跟我交流。 
  17.  * 我的msn:egg.chenlw@gmail.com 
  18.  *    QQ:372133556(注上为什么加我就可以了) 
  19.  * 我的blog:http://hi.baidu.com/egg_chen 
  20.  * 欢迎交流 
  21.  */  
  22. public class Trans2RMB {  
  23.   
  24.     /** 
  25.      * 测试程序的可行性 
  26.      * @param args 
  27.      */  
  28.     public static void main(String[] args) {  
  29.         System.out.println("\n--------将数字转换成中文金额的大写形式------------\n");  
  30.         Trans2RMB t2r = new Trans2RMB();  
  31.         String s = t2r.cleanZero(t2r.splitNum(t2r.roundString(t2r.getNum())));  
  32.         // 如果转换过后是一个空串,则不输出屏幕  
  33.         if(!"".equals(s)) {  
  34.             System.out.println("转换成中文后为:" + s);;  
  35.         }  
  36.         System.out.println("\n---------------------------------------------");  
  37.     }  
  38.       
  39.     /** 
  40.      * 从命令行接收一个数,在其中调用 checkNum() 方法对其进行 
  41.      * 验证,并返回相应的值 
  42.      * @return 如果输入合法,返回输入的这个数 
  43.      */  
  44.     private String getNum() {  
  45.         String s = null;  
  46.         System.out.println("请输入一个数字(精确到小数点后两位):");  
  47.         // 从命令行输入这个浮点数  
  48.         java.util.Scanner scanner = new java.util.Scanner(System.in);  
  49.         s = scanner.next();  
  50.         // 关闭这个Scanner  
  51.         scanner.close();  
  52.         // 判断用户输入是否合法  
  53.         // 若合法,返回这个值;若非法返回 "0"  
  54.         if(this.checkNum(s)) {  
  55.             return s;  
  56.         } else {  
  57.             return "";  
  58.         }  
  59.     }  
  60.       
  61.     /** 
  62.      * 判断用户输入的数据是否合法,用户只能输入大于零的数字,不能输入其它字符 
  63.      * @param s String 
  64.      * @return 如果用户输入数据合法,返回 true,否则返回 false 
  65.      */  
  66.     private boolean checkNum(String s) {  
  67.         // 如果用户输入的数里有非数字字符,则视为非法数据,返回 false  
  68.         try {  
  69.             float f = Float.valueOf(s);  
  70.             // 如果这个数小于零则视为非法数据,返回 false  
  71.             if(f < 0) {  
  72.                 System.out.println("非法数据,请检查!");  
  73.                 return false;  
  74.             }else {  
  75.                 return true;  
  76.             }  
  77.         } catch (NumberFormatException e) {  
  78.             System.out.println("非法数据,请检查!");  
  79.             return false;  
  80.         }     
  81.     }  
  82.       
  83.     /** 
  84.      * 把用户输入的数以小数点为界分割开来,并调用 numFormat() 方法 
  85.      * 进行相应的中文金额大写形式的转换 
  86.      * 注:传入的这个数应该是经过 roundString() 方法进行了四舍五入操作的 
  87.      * @param s String 
  88.      * @return 转换好的中文金额大写形式的字符串 
  89.      */  
  90.     private String splitNum(String s) {  
  91.         // 如果传入的是空串则继续返回空串  
  92.         if("".equals(s)) {  
  93.             return "";  
  94.         }  
  95.         // 以小数点为界分割这个字符串  
  96.         int index = s.indexOf(".");  
  97.         // 截取并转换这个数的整数部分  
  98.         String intOnly = s.substring(0, index);  
  99.         String part1 = this.numFormat(1, intOnly);  
  100.         // 截取并转换这个数的小数部分  
  101.         String smallOnly = s.substring(index + 1);  
  102.         String part2 = this.numFormat(2, smallOnly);  
  103.         // 把转换好了的整数部分和小数部分重新拼凑一个新的字符串  
  104.         String newS = part1 + part2;  
  105.         return newS;  
  106.     }  
  107.           
  108.     /** 
  109.      * 对传入的数进行四舍五入操作 
  110.      * @param s String 从命令行输入的那个数 
  111.      * @return 四舍五入后的新值 
  112.      */  
  113.     private String roundString(String s) {  
  114.         // 如果传入的是空串则继续返回空串  
  115.         if("".equals(s)) {  
  116.             return "";  
  117.         }  
  118.         // 将这个数转换成 double 类型,并对其进行四舍五入操作  
  119.         double d = Double.parseDouble(s);  
  120.         // 此操作作用在小数点后两位上  
  121.         d = (d * 100 + 0.5) / 100;  
  122.         // 将 d 进行格式化  
  123.         s = new java.text.DecimalFormat("##0.000").format(d);  
  124.         // 以小数点为界分割这个字符串  
  125.         int index = s.indexOf(".");  
  126.         // 这个数的整数部分  
  127.         String intOnly = s.substring(0, index);  
  128.         // 规定数值的最大长度只能到万亿单位,否则返回 "0"  
  129.         if(intOnly.length() > 13) {  
  130.             System.out.println("输入数据过大!(整数部分最多13位!)");  
  131.             return "";  
  132.         }  
  133.         // 这个数的小数部分  
  134.         String smallOnly = s.substring(index + 1);  
  135.         // 如果小数部分大于两位,只截取小数点后两位  
  136.         if(smallOnly.length() > 2) {  
  137.             String roundSmall = smallOnly.substring(0, 2);  
  138.             // 把整数部分和新截取的小数部分重新拼凑这个字符串  
  139.             s = intOnly + "." + roundSmall;  
  140.         }  
  141.         return s;  
  142.     }  
  143.       
  144.     /** 
  145.      * 把传入的数转换为中文金额大写形式 
  146.      * @param flag int 标志位,1 表示转换整数部分,0 表示转换小数部分 
  147.      * @param s String 要转换的字符串 
  148.      * @return 转换好的带单位的中文金额大写形式 
  149.      */  
  150.     private String numFormat(int flag, String s) {  
  151.         int sLength = s.length();  
  152.         // 货币大写形式  
  153.         String bigLetter[] = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};  
  154.         // 货币单位  
  155.         String unit[] = {"元", "拾", "佰", "仟", "万",   
  156.                 // 拾万位到仟万位  
  157.                 "拾", "佰", "仟",  
  158.                 // 亿位到万亿位  
  159.                 "亿", "拾", "佰", "仟", "万"};  
  160.         String small[] = {"分", "角"};  
  161.         // 用来存放转换后的新字符串  
  162.         String newS = "";  
  163.         // 逐位替换为中文大写形式  
  164.         for(int i = 0; i < sLength; i ++) {  
  165.             if(flag == 1) {  
  166.                 // 转换整数部分为中文大写形式(带单位)  
  167.                 newS = newS + bigLetter[s.charAt(i) - 48] + unit[sLength - i - 1];  
  168.             } else if(flag == 2) {  
  169.                 // 转换小数部分(带单位)  
  170.                 newS = newS + bigLetter[s.charAt(i) - 48] + small[sLength - i - 1];  
  171.             }  
  172.         }  
  173.         return newS;  
  174.     }  
  175.       
  176.     /** 
  177.      * 把已经转换好的中文金额大写形式加以改进,清理这个字 
  178.      * 符串里面多余的零,让这个字符串变得更加可观 
  179.      * 注:传入的这个数应该是经过 splitNum() 方法进行处理,这个字 
  180.      * 符串应该已经是用中文金额大写形式表示的 
  181.      * @param s String 已经转换好的字符串 
  182.      * @return 改进后的字符串 
  183.      */  
  184.     private String cleanZero(String s) {  
  185.         // 如果传入的是空串则继续返回空串  
  186.         if("".equals(s)) {  
  187.             return "";  
  188.         }  
  189.         // 如果用户开始输入了很多 0 去掉字符串前面多余的'零',使其看上去更符合习惯  
  190.         while(s.charAt(0) == '零') {  
  191.             // 将字符串中的 "零" 和它对应的单位去掉  
  192.             s = s.substring(2);  
  193.             // 如果用户当初输入的时候只输入了 0,则只返回一个 "零"  
  194.             if(s.length() == 0) {  
  195.                 return "零";  
  196.             }  
  197.         }  
  198.         // 字符串中存在多个'零'在一起的时候只读出一个'零',并省略多余的单位  
  199.         /* 由于本人对算法的研究太菜了,只能用4个正则表达式去转换了,各位大虾别介意哈... */  
  200.         String regex1[] = {"零仟", "零佰", "零拾"};  
  201.         String regex2[] = {"零亿", "零万", "零元"};  
  202.         String regex3[] = {"亿", "万", "元"};  
  203.         String regex4[] = {"零角", "零分"};  
  204.         // 第一轮转换把 "零仟", 零佰","零拾"等字符串替换成一个"零"  
  205.         for(int i = 0; i < 3; i ++) {  
  206.             s = s.replaceAll(regex1[i], "零");  
  207.         }  
  208.         // 第二轮转换考虑 "零亿","零万","零元"等情况  
  209.         // "亿","万","元"这些单位有些情况是不能省的,需要保留下来  
  210.         for(int i = 0; i < 3; i ++) {  
  211.             // 当第一轮转换过后有可能有很多个零叠在一起  
  212.             // 要把很多个重复的零变成一个零  
  213.             s = s.replaceAll("零零零", "零");  
  214.             s = s.replaceAll("零零", "零");  
  215.             s = s.replaceAll(regex2[i], regex3[i]);  
  216.         }  
  217.         // 第三轮转换把"零角","零分"字符串省略  
  218.         for(int i = 0; i < 2; i ++) {  
  219.             s = s.replaceAll(regex4[i], "");  
  220.         }  
  221.         // 当"万"到"亿"之间全部是"零"的时候,忽略"亿万"单位,只保留一个"亿"  
  222.         s = s.replaceAll("亿万", "亿");  
  223.         return s;  
  224.     }  
  225. }