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

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

数字转汉字的原理:

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

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

    //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” 转换成“一亿零一”而非“一亿零万零一”。

这里只分享了一个转换汉字的功能,下篇将分享一下大数相乘、相加、相减的方法。支持小数和负数的运算,敬请期待。

时间: 2024-12-02 23:16:36

Java工作利器之常用工具类(一)——数字工具类-数字转汉字的相关文章

Java工作利器之常用工具类(三)——字符串工具类-智能截取

前两篇博文简单分享了一下数字工具类,现在说说字符串工具类. 相信大家都自己封装过或者用过guava封装的Strings,但是有没有可以智能截取,比如说"截取整数第二个到倒数第二个"的字符串.你是否还需要自己写str.substring(1,str.length()-2).如果是的话,请继续往下看吧.暂时还未见过可以反向截取字符串的.一般都是substring(str, start, end)或者substring(str, len);而这里的参数都必须是正数,否则就会报错.所以为了改善

Java工作利器之常用工具类(四)——Json工具类,使用正则支持xml与json互转

看到这个题目是不是大部分人都不屑一顾,的确基本上每个java程序猿都写过json工具类,也有很多人都使用json-lib.jar封装过类似的功能,但是我这里使用了正则来支持xml与json的互转,减少了jar包的引入.基本上满足了需求.当然如果你需要更强大的功能,还是最好使用json-lib来实现. 主要看一下工具类中的转换json和转换成xml的方法吧. 1. xml转json 具体就不多说了,我是采用的笨方法,多次使用正则进行替换的.比较好的一点儿是支持xml元素属性.如果xml节点有属性会

Java工作利器之常用工具类(二)——数字工具类-大数乘法、加法、减法运算

上篇分享了一下数字转汉字的小功能,这里再分享一下大数相乘.相加.相减的功能.其他的不做过多的铺垫了,我先讲一下各个功能的计算原理. Ⅰ. 乘法运算 为什么先说乘法运算--因为我先做了乘法运算.其实思路也是很多的,但是最终我参考了网络上的一种计算方案,然后做了很多的修改.感觉这个在思路上应该是比较简单的. 简单点说:把数拆分成整数小数分别进行乘法运算,然后将结果放入一个特定长度的数组中,在放入是要计算存放的偏移位置,最后再对这个进行处理(进位.标记等),得到最终的结果. 是不是有点晕.请我详细说一

计算java常用类型字节大小的工具类

问题描述 /***Name:Sizeof.java*Copyright:zhaozhihua**/packagecom.tywire.tadu.utils;importjava.lang.reflect.Array;importjava.lang.reflect.Field;importjava.lang.reflect.Modifier;importjava.util.Enumeration;importjava.util.HashMap;importjava.util.Hashtable;i

Java程序连接数据库的常用的类和接口介绍_java

编写访问数据库的Java程序还需要几个重要的类和接口.DriverManager类 DriverManager类处理驱动程序的加载和建立新数据库连接.DriverManager是java.sql包中用于管理数据库驱动程序的类.通常,应用程序只使用类DriverManager的getConnection()静态方法,用来建立与数据库的连接,返回Connection对象: static Connection getConnection(String url,String username,Strin

java连接数据库增、删、改、查工具类_java

java连接数据库增.删.改.查工具类 数据库操作工具类,因为各厂家数据库的分页条件不同,目前支持Mysql.Oracle.Postgresql的分页查询在Postgresql环境测试过了,其他数据库未测试.sql语句需要使用预编译形式的 复制代码 代码如下: package db; import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.R

请问数字媒体技术常用的软硬件开发平台及工具有哪些,本人新手,想对数媒有所了解,请大神赐教

问题描述 请问数字媒体技术常用的软硬件开发平台及工具有哪些,本人新手,想对数媒有所了解,请大神赐教 请问数字媒体技术常用的软硬件开发平台有哪些,跪谢,本人新手,想对数媒有所了解,请大神赐教 解决方案 数字媒体技术主要包含场景设计.角色形象设计.游戏程序设计.多媒体后期处理.人机交互技术.主要针对游戏开发和网站美工还有创意设计这类工作设计的专业. IBM的数字媒体工厂解决方案是一个将IBM的技术统一起来的开放式框架,包含了IBM的硬件.软件和服务. 主要涉及:摄影摄像技术.艺术设计基础.数字媒体技

测试人必备的5类测试辅助工具

阿基米德说:"给我一根杠杆和一个支点,我将撬起整个地球" -这就是工具的力量. 我们常常在DiggerPlus上分享各种性能测试工具,自动化测试工具,安全渗透测试工具等,但是我们今天要分享的这5款工具,对于测试人的日常工作来说也非常重要,而且也非常常用,重新提起他们,是因为他们很多时候被我们忽略了. 测试人必备的5类测试辅助工具 测试工具 下面,我们将罗列出这5类测试辅助工具,不要感到惊讶,确实,他们就在每一位测试人身边: 1. Excel 2. 截图工具 3. 打包/压缩解压缩工具

常用的Facebook Apps实用工具

Facebook平台下的有很多优秀的Apps实用工具,大量的第三方工具极大扩展了Facebook的功能和应用,给Facebook带来了巨大的成功.在Facebook海量的实用工具中,我挑选了几个优秀的Apps推荐给大家,安装后会令大家的Facebook功能得到很大的增强,以下是这些应用程序清单和介绍. Twitter - 可以将Twitter发布的信息同步到Facebook,也可以在Facebook发布信息到Twitter上,这是Twitter官方页面推荐的实用工具,同步速度非常快,Twitte