Java工作利器之常用工具类(一)——数字工具类-数字转汉字

本人是从事互联网金融行业的,所以会接触到一些金融类的问题,常见的一种就是数字转汉字大小写的问题。所以抽空就写了一个小小的工具类,实现了数字转汉字、大数相加、相减、相乘的工具类,希望能帮助有需求的同行们。本篇就分享一下数字转化为汉字的思路吧。

 
数字转汉字的原理:
  1. 拆分:由于整数部分要加权值,而小数部分直接转换即可,所以首先要将数字拆分成整数+小数;
  2. 整数处理:按照我们的中国人的习惯,把数字格式化成4位一组,不足4位前面补0。每次处理4位,按位匹配数组中的汉字+权值。即按照数值找数字数组(num_lower 、num_upper )中对应位置的汉字,按照在4位中的偏移量在单位权值数组(unit_lower 、unit_upper )中找。比如21,转化4位为0021,前面的0不用管,2对应数字“二”,权值是“十”,1对应数字“一”,权值是“(个)”用空字符串代替。即得到“二十一”。每4位处理完后,还要整体对应一个权值,比如“万、亿、兆”等;
  3. 小数处理:小数部分直接按位对应汉字数组和权值即可。
废话了这么多,可能云里雾里的,看看具体代码吧:
  1. //num 表示数字,lower表示小写,upper表示大写  
  2. private static final String[] num_lower = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" };  
  3. private static final String[] num_upper = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" };  
  4.   
  5. //unit 表示单位权值,lower表示小写,upper表示大写  
  6. private static final String[] unit_lower = { "", "十", "百", "千" };  
  7. private static final String[] unit_upper = { "", "拾", "佰", "仟"};  
  8. private static final String[] unit_common = {"","万", "亿","兆","京","垓","秭","穰","沟","涧","正","载"};  
  9.   
  10. //允许的格式  
  11. private static final List<String> promissTypes = Arrays.asList("INTEGER","INT","LONG","DECIMAL","FLOAT","DOUBLE","STRING","BYTE","TYPE","SHORT");  
  12.   
  13. /** 
  14.  * 数字转化为小写的汉字 
  15.  *  
  16.  * @param num 将要转化的数字 
  17.  * @return 
  18.  */  
  19. public static String toChineseLower(Object num){  
  20.     return format(num, num_lower, unit_lower);  
  21. }  
  22.   
  23. /** 
  24.  *  数字转化为大写的汉字 
  25.  *   
  26.  * @param num 将要转化的数字 
  27.  * @return 
  28.  */  
  29. public static String toChineseUpper(Object num){  
  30.     return format(num, num_upper, unit_upper);  
  31. }  
  32.   
  33. /** 
  34.  * 格式化数字 
  35.  *  
  36.  * @param num            原数字 
  37.  * @param numArray     数字大小写数组 
  38.  * @param unit            单位权值 
  39.  * @return 
  40.  */  
  41. private static String format(Object num,String[] numArray,String[] unit){  
  42.     if(!promissTypes.contains(num.getClass().getSimpleName().toUpperCase())){  
  43.         throw new RuntimeException("不支持的格式类型");  
  44.     }  
  45.     //获取整数部分  
  46.     String intnum = getInt(String.valueOf(num));  
  47.     //获取小数部分  
  48.     String decimal = getFraction(String.valueOf(num));  
  49.     //格式化整数部分  
  50.     String result = formatIntPart(intnum,numArray,unit);  
  51.     if(!"".equals(decimal)){//小数部分不为空  
  52.         //格式化小数  
  53.         result += "点"+formatFractionalPart(decimal, numArray);  
  54.     }  
  55.     return result;  
  56. }  
  57.   
  58. /** 
  59.  * 格式化整数部分 
  60.  *  
  61.  * @param num    整数部分 
  62.  * @param numArray 数字大小写数组 
  63.  * @return 
  64.  */  
  65. private static String formatIntPart(String num,String[] numArray,String[] unit){  
  66.   
  67.     //按4位分割成不同的组(不足四位的前面补0)  
  68.     Integer[] intnums = split2IntArray(num);  
  69.   
  70.     boolean zero = false;  
  71.     StringBuffer sb = new StringBuffer();  
  72.     for(int i=0;i<intnums.length;i++){  
  73.         //格式化当前4位  
  74.         String r = formatInt(intnums[i], numArray,unit);  
  75.         if("".equals(r)){//  
  76.             if((i+1)==intnums.length){  
  77.                 sb.append(numArray[0]);//结果中追加“零”  
  78.             }else{  
  79.                 zero=true;  
  80.             }  
  81.         }else{//当前4位格式化结果不为空(即不为0)  
  82.             if(zero || (i>0 && intnums[i]<1000)){//如果前4位为0,当前4位不为0  
  83.                 sb.append(numArray[0]);//结果中追加“零”  
  84.             }  
  85.             sb.append(r);  
  86.             sb.append(unit_common[intnums.length-1-i]);//在结果中添加权值  
  87.             zero=false;  
  88.         }  
  89.     }  
  90.     return sb.toString();  
  91. }  
  92.   
  93. /** 
  94.  * 格式化小数部分 
  95.  *  
  96.  * @param decimal 小数部分 
  97.  * @param numArray 数字大小写数组 
  98.  * @return 
  99.  */  
  100. private static String formatFractionalPart(String decimal,String[] numArray) {  
  101.     char[] val = String.valueOf(decimal).toCharArray();  
  102.     int len = val.length;  
  103.     StringBuilder sb = new StringBuilder();  
  104.     for (int i = 0; i < len; i++) {  
  105.         int n = Integer.valueOf(val[i] + "");  
  106.         sb.append(numArray[n]);  
  107.     }  
  108.     return sb.toString();  
  109. }  
拆分整数和小数的方法在这里:
  1. /** 
  2.  * 获取整数部分 
  3.  *  
  4.  * @param num 
  5.  * @return 
  6.  */  
  7. private static String getInt(String num){  
  8.     //检查格式  
  9.     checkNum(num);  
  10.   
  11.     char[] val = String.valueOf(num).toCharArray();  
  12.     StringBuffer sb = new StringBuffer();  
  13.     int t , s = 0;  
  14.     for (int i = 0; i < val.length; i++) {  
  15.         if(val[i]=='.') {  
  16.             break;  
  17.         }  
  18.         t = Integer.parseInt(val[i]+"",16);  
  19.         if(s+t==0){  
  20.             continue;  
  21.         }  
  22.         sb.append(t);  
  23.         s+=t;  
  24.     }  
  25.     return (sb.length()==0? "0":sb.toString());  
  26. }  
  27.   
  28. /** 
  29.  * 获取小数部分 
  30.  *  
  31.  * @param num 
  32.  * @return 
  33.  */  
  34. private static String getFraction(String num){  
  35.     int i = num.lastIndexOf(".");  
  36.     if(num.indexOf(".") != i){  
  37.         throw new RuntimeException("数字格式不正确,最多只能有一位小数点!");  
  38.     }  
  39.     String fraction ="";   
  40.     if(i>=0){  
  41.         fraction = getInt(new StringBuffer(num).reverse().toString());  
  42.         if(fraction.equals("0")){  
  43.             return "";  
  44.         }  
  45.     }  
  46.     return new StringBuffer(fraction).reverse().toString();  
  47. }  
  48.   
  49. /** 
  50.  * 检查数字格式 
  51.  *  
  52.  * @param num 
  53.  */  
  54. private static void checkNum(String num) {  
  55.     if(num.indexOf(".") != num.lastIndexOf(".")){  
  56.         throw new RuntimeException("数字["+num+"]格式不正确!");  
  57.     }  
  58.     if(num.indexOf("-") != num.lastIndexOf("-") || num.lastIndexOf("-")>0){  
  59.         throw new RuntimeException("数字["+num+"]格式不正确!");  
  60.     }  
  61.     if(num.indexOf("+") != num.lastIndexOf("+")){  
  62.         throw new RuntimeException("数字["+num+"]格式不正确!");  
  63.     }  
  64.     if(num.indexOf("+") != num.lastIndexOf("+")){  
  65.         throw new RuntimeException("数字["+num+"]格式不正确!");  
  66.     }  
  67.     if(num.replaceAll("[\\d|\\.|\\-|\\+]", "").length()>0){  
  68.         throw new RuntimeException("数字["+num+"]格式不正确!");  
  69.     }  
  70. }  
通过这种分而治之的思路,处理起来就简单多了。写个main函数调用一下:
  1. public static void main(String[] args) {  
  2.     short s = 10;  
  3.     byte b=10;  
  4.     char c='A';  
  5.     Object[] nums = {s, b, c, 0, 1001, 100100001L, 21., 205.23F, 205.23D, "01000010", "1000000100105.0123", ".142", "20.00", "1..2", true};  
  6.     System.out.println("将任意数字转化为汉字(包括整数、小数以及各种类型的数字)");  
  7.     System.out.println("--------------------------------------------");  
  8.     for(Object num :nums){  
  9.         try{  
  10.             System.out.print("["+num.getClass().getSimpleName()+"]"+num);  
  11.             for(int i=0;i<25-String.valueOf(num+num.getClass().getSimpleName()).length();i+=4){  
  12.                 System.out.print("\t");  
  13.             }  
  14.             //调用转化为小写和大写  
  15.             System.out.print(" format:"+toChineseLower(num));  
  16.             System.out.println("【"+toChineseUpper(num)+"】");  
  17.         }catch(Exception e){  
  18.             System.out.println(" 错误信息:"+e.getMessage());  
  19.         }  
  20.     }  
  21. }  

看看结果吧:

从上述代码和运行结果中,我们可以看到该功能支持多种数据类型的转换、支持转化为一般汉字和财务专用大写汉字。还可以智能处理非正常逻辑的数字。比如“20”会转化为“二十”而非“二十零”;“1 0000 0001” 转换成“一亿零一”而非“一亿零万零一”。
 
这里只分享了一个转换汉字的功能,下篇将分享一下大数相乘、相加、相减的方法。支持小数和负数的运算,敬请期待。
 
 
完整代码:
/**
 * 数字转汉字工具类
 *
 * @author arron
 * @date 2015年7月21日 下午4:14:16
 * @version 1.0
 */
public class NumUtils {

    //num 表示数字,lower表示小写,upper表示大写
    private static final String[] num_lower = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" };
    private static final String[] num_upper = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" };

    //unit 表示单位权值,lower表示小写,upper表示大写
    private static final String[] unit_lower = { "", "十", "百", "千" };
    private static final String[] unit_upper = { "", "拾", "佰", "仟"};
    private static final String[] unit_common = {"","万", "亿","兆","京","垓","秭","穰","沟","涧","正","载"};

    //允许的格式
    private static final List<String> promissTypes = Arrays.asList("INTEGER","INT","LONG","DECIMAL","FLOAT","DOUBLE","STRING","BYTE","TYPE","SHORT");

    //标记为小数点
    private static final int DOT=-99;
    //标记为无效数字
    private static final int INVALID=-100;


    /**
     * 数字转化为小写的汉字
     *
     * @param num 将要转化的数字
     * @return
     */
    public static String toChineseLower(Object num){
        return format(num, num_lower, unit_lower);
    }

    /**
     *  数字转化为大写的汉字
     *
     * @param num 将要转化的数字
     * @return
     */
    public static String toChineseUpper(Object num){
        return format(num, num_upper, unit_upper);
    }

    /**
     * 格式化数字
     *
     * @param num			原数字
     * @param numArray 	数字大小写数组
     * @param unit			单位权值
     * @return
     */
    private static String format(Object num,String[] numArray,String[] unit){
        if(!promissTypes.contains(num.getClass().getSimpleName().toUpperCase())){
            throw new RuntimeException("不支持的格式类型");
        }
        //获取整数部分
        String intnum = getInt(String.valueOf(num));
        //获取小数部分
        String decimal = getFraction(String.valueOf(num));
        //格式化整数部分
        String result = formatIntPart(intnum,numArray,unit);
        if(!"".equals(decimal)){//小数部分不为空
            //格式化小数
            result += "点"+formatFractionalPart(decimal, numArray);
        }
        return result;
    }


    /**
     * 获取整数部分
     *
     * @param num
     * @return
     */
    private static String getInt(String num){
        //检查格式
        checkNum(num);

        char[] val = String.valueOf(num).toCharArray();
        StringBuffer sb = new StringBuffer();
        int t , s = 0;
        for (int i = 0; i < val.length; i++) {
            if(val[i]=='.') {
                break;
            }
            t = Integer.parseInt(val[i]+"",16);
            if(s+t==0){
                continue;
            }
            sb.append(t);
            s+=t;
        }
        return (sb.length()==0? "0":sb.toString());
    }

    /**
     * 检查数字格式
     *
     * @param num
     */
    private static void checkNum(String num) {
        if(num.indexOf(".") != num.lastIndexOf(".")){
            throw new RuntimeException("数字["+num+"]格式不正确!");
        }
        if(num.indexOf("-") != num.lastIndexOf("-") || num.lastIndexOf("-")>0){
            throw new RuntimeException("数字["+num+"]格式不正确!");
        }
        if(num.indexOf("+") != num.lastIndexOf("+")){
            throw new RuntimeException("数字["+num+"]格式不正确!");
        }
        if(num.indexOf("+") != num.lastIndexOf("+")){
            throw new RuntimeException("数字["+num+"]格式不正确!");
        }
        if(num.replaceAll("[\\d|\\.|\\-|\\+]", "").length()>0){
            throw new RuntimeException("数字["+num+"]格式不正确!");
        }
    }

    /**
     * 获取小数部分
     *
     * @param num
     * @return
     */
    private static String getFraction(String num){
        int i = num.lastIndexOf(".");
        if(num.indexOf(".") != i){
            throw new RuntimeException("数字格式不正确,最多只能有一位小数点!");
        }
        String fraction ="";
        if(i>=0){
            fraction = getInt(new StringBuffer(num).reverse().toString());
            if(fraction.equals("0")){
                return "";
            }
        }
        return new StringBuffer(fraction).reverse().toString();
    }

    /**
     * 分割数字,每4位一组
     *
     * @param num
     * @return
     */
    private static Integer[] split2IntArray(String num){
        String prev = num.substring(0,num.length() % 4);
        String stuff = num.substring(num.length() % 4);
        if(!"".equals(prev)){
            num = String.format("%04d",Integer.valueOf(prev))+stuff;
        }
        Integer[] ints = new Integer[num.length()/4];
        int idx=0;
        for(int i=0;i<num.length();i+=4){
            String n = num.substring(i,i+4);
            ints[idx++]=Integer.valueOf(n);
        }
        return ints;
    }

    /**
     * 格式化整数部分
     *
     * @param num	整数部分
     * @param numArray 数字大小写数组
     * @return
     */
    private static String formatIntPart(String num,String[] numArray,String[] unit){

        //按4位分割成不同的组(不足四位的前面补0)
        Integer[] intnums = split2IntArray(num);

        boolean zero = false;
        StringBuffer sb = new StringBuffer();
        for(int i=0;i<intnums.length;i++){
            //格式化当前4位
            String r = formatInt(intnums[i], numArray,unit);
            if("".equals(r)){//
                if((i+1)==intnums.length){
                    sb.append(numArray[0]);//结果中追加“零”
                }else{
                    zero=true;
                }
            }else{//当前4位格式化结果不为空(即不为0)
                if(zero || (i>0 && intnums[i]<1000)){//如果前4位为0,当前4位不为0
                    sb.append(numArray[0]);//结果中追加“零”
                }
                sb.append(r);
                sb.append(unit_common[intnums.length-1-i]);//在结果中添加权值
                zero=false;
            }
        }
        return sb.toString();
    }

    /**
     * 格式化小数部分
     *
     * @param decimal 小数部分
     * @param numArray 数字大小写数组
     * @return
     */
    private static String formatFractionalPart(String decimal,String[] numArray) {
        char[] val = String.valueOf(decimal).toCharArray();
        int len = val.length;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < len; i++) {
            int n = Integer.valueOf(val[i] + "");
            sb.append(numArray[n]);
        }
        return sb.toString();
    }


    /**
     * 格式化4位整数
     *
     * @param num
     * @param numArray
     * @return
     */
    private static String formatInt(int num,String[] numArray,String[] unit){
        char[] val = String.valueOf(num).toCharArray();
        int len = val.length;
        StringBuilder sb = new StringBuilder();
        boolean isZero = false;
        for (int i = 0; i < len; i++) {
            int n = Integer.valueOf(val[i] + "");//获取当前位的数值
            if (n==0) {
                isZero = true;
            } else {
                if (isZero) {
                    sb.append(numArray[Integer.valueOf(val[i-1] + "")]);
                }
                sb.append(numArray[n]);
                sb.append(unit[(len - 1) - i]);
                isZero=false;
            }
        }
        return sb.toString();
    }

    public static void main(String[] args) {
		short s = 10;
		byte b=10;
		char c='A';
		Object[] nums = {s, b, c, 0, 1001, 100100001L, 21., 205.23F, 205.23D, "01000010", "1000000100105.0123", ".142", "20.00", "1..2", true};
		System.out.println("将任意数字转化为汉字(包括整数、小数以及各种类型的数字)");
		System.out.println("--------------------------------------------");
		for(Object num :nums){
			try{
				System.out.print("["+num.getClass().getSimpleName()+"]"+num);
				for(int i=0;i<25-String.valueOf(num+num.getClass().getSimpleName()).length();i+=4){
					System.out.print("\t");
				}
				System.out.print(" format:"+toChineseLower(num));
				System.out.println("【"+toChineseUpper(num)+"】");
			}catch(Exception e){
				System.out.println(" 错误信息:"+e.getMessage());
			}
		}
    }
}
 
 转自:https://blog.csdn.net/xiaoxian8023/article/details/49834589
 

猜你喜欢

转载自z1414644039.iteye.com/blog/2418285