数字工具类-数字转汉字

数字转汉字的原理:

    拆分:由于整数部分要加权值,而小数部分直接转换即可,所以首先要将数字拆分成整数+小数;
    整数处理:按照我们的中国人的习惯,把数字格式化成4位一组,不足4位前面补0。每次处理4位,按位匹配数组中的汉字+权值。即按照数值找数字数组(num_lower 、num_upper )中对应位置的汉字,按照在4位中的偏移量在单位权值数组(unit_lower 、unit_upper )中找。比如21,转化4位为0021,前面的0不用管,2对应数字“二”,权值是“十”,1对应数字“一”,权值是“(个)”用空字符串代替。即得到“二十一”。每4位处理完后,还要整体对应一个权值,比如“万、亿、兆”等;
    小数处理:小数部分直接按位对应汉字数组和权值即可。

废话了这么多,可能云里雾里的,看看具体代码吧:

        //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");
     
        /**
         * 数字转化为小写的汉字
         *
         * @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    整数部分
         * @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();
        }

拆分整数和小数的方法在这里:

        /**
         * 获取整数部分
         *
         * @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
         * @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();
        }
     
        /**
         * 检查数字格式
         *
         * @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+"]格式不正确!");
            }
        }

通过这种分而治之的思路,处理起来就简单多了。写个main函数调用一下:

        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());
                }
            }
        }


看看结果吧:

从上述代码和运行结果中,我们可以看到该功能支持多种数据类型的转换、支持转化为一般汉字和财务专用大写汉字。还可以智能处理非正常逻辑的数字。比如“20”会转化为“二十”而非“二十零”;“1 0000 0001” 转换成“一亿零一”而非“一亿零万零一”。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值