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” 轉換成“一億零一”而非“一億零萬零一”。

工具類包代碼已分享到github上:https://github.com/Arronlong/commonutils

當前工具類代碼(可能博文中的代碼略有出入):https://github.com/Arronlong/commonutils/blob/master/src/main/java/com/arronlong/common/util/num/NumUtils.java

這裏只分享了一個轉換漢字的功能,下篇將分享一下大數相乘、相加、相減的方法。支持小數和負數的運算,敬請期待。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章