天天看點

java人民币數字轉換中文大寫(精确到人民币大寫分)

import java.math.BigDecimal;

/**
 * Class Description : 該類是把阿拉伯數字轉換成中文大寫的類。
 * <p>
 * <p>
 * <p>
 * 漢字大寫金額數字,一律用正楷字或行書字書寫,如壹、貳、叁、肆、伍、陸、柒、捌、玖、拾、佰、仟、萬、億、圓(元)、
 * 角、分、零、整(正)等易于辨認、不易塗改的字樣。
 * 不得用一、二(兩)、三、四、五、六、七、八、九、十、念、毛、另(或0)等字樣代替,不得任意自造台灣字。
 * <p>
 * 大寫金額數字到元或角為止的,在“元”或“角”字之後應寫“整”或“正”字;大寫金額數字有分的,分字後面不寫“整”字。
 * 大寫金額數字前未印有人民币字樣的,應加填“人民币”三字,“人民币”三字與金額數字之間不得留有空白。
 * <p>
 * 阿拉伯金額數字中間有“0”時,漢字大寫金額要寫“零”字,如$101.50,漢字大寫金額應寫成人民币壹佰零壹圓伍角整。
 * 阿拉伯金額數字中間連續有幾個“0”時,漢字大寫金額中可以隻寫一個“零”字,如¥1,004.56,漢字大寫金額應寫成
 * 人民币壹仟零肆圓伍角陸分。阿拉伯金額數字元位是“0”,或數字中間連續有幾個“0”,元位也是“0”,但角位不是“0”時,
 * 漢字大寫金額可隻寫一個“零”字,也可不寫“零”字,如$1,320.56,漢字大寫金額應寫成人民币壹仟叁佰貳拾圓零伍
 * 角陸分,或人民币壹仟叁佰貳拾圓伍角陸分。又如$1,000.56,漢字大寫金額應寫成人民币壹仟圓零伍角陸分,或人民
 * 币壹仟圓伍角陸分。
 * <p>
 * 摘自《會計人員工作規則》(84)财會16号
 */
public class NumberToChineseUtil {
    private final static String HanDigiStr[] = new String[]{"零", "壹", "貳", "叁", "肆", "伍", "陸",
            "柒", "捌", "玖"};

    private final static String HanDiviStr[] = new String[]{"", "拾", "佰", "仟", "萬", "拾", "佰", "仟",
            "億", "拾", "佰", "仟", "萬", "拾", "佰", "仟", "億", "拾", "佰", "仟", "萬",
            "拾", "佰", "仟"};

    /**
     * 負責把小數點前面的數轉換為大寫中文
     *
     * 輸入字元串必須正整數,隻允許前面有空格(必須右對齊),不允許前面有零
     *
     * @param numberStr
     * @return
     */
    private static String positiveIntegerToHanString(String numberStr) {
        String RMBStr = "";
        boolean lastzero = false;
        boolean hasvalue = false; // 億、萬進位前有數值标記
        int len, n;
        len = numberStr.length();
        if (len > 15)
            return "金額過大!";
        for (int i = len - 1; i >= 0; i--) {
            if (numberStr.charAt(len - i - 1) == ' ')
                continue;
            n = numberStr.charAt(len - i - 1) - '0';
            if (n < 0 || n > 9)
                return "金額含非數字字元!";

            if (n != 0) {
                if (lastzero)
                    RMBStr += HanDigiStr[0]; // 若幹零後若跟非零值,隻顯示一個零
                // 除了億萬前的零不帶到後面
                // if( !( n==1 && (i%4)==1 && (lastzero || i==len-1) ) ) //
                // 如十進位前有零也不發壹音用此行
//              if (!(n == 1 && (i % 4) == 1 && i == len - 1)) // 十進位處于第一位不發壹音
                RMBStr += HanDigiStr[n];
                RMBStr += HanDiviStr[i]; // 非零值後加進位,個位為空
                hasvalue = true; // 置萬進位前有值标記

            } else {
                if ((i % 8) == 0 || ((i % 8) == 4 && hasvalue)) // 億萬之間必須有非零值方顯示萬
                    RMBStr += HanDiviStr[i]; // “億”或“萬”
            }
            if (i % 8 == 0)
                hasvalue = false; // 萬進位前有值标記逢億複位
            lastzero = (n == 0) && (i % 4 != 0);
        }

        if (RMBStr.length() == 0)
            return HanDigiStr[0]; // 輸入空字元或"0",傳回"零"
        return RMBStr;
    }

    /**
     * 輸入double型數轉換為大寫中文
     *
     * @param doubleValue
     * @return 大寫中文
     */
    public static String getChineseMoneyStringForDoubleVal(double doubleValue) {
        String SignStr = "";
        String TailStr = "";
        long fraction, integer;
        int jiao, fen;

        if (doubleValue < 0) {
            doubleValue = -doubleValue;
            SignStr = "負";
        }
        if (doubleValue > 99999999999999.999
                || doubleValue < -99999999999999.999)
            return "金額數值位數過大!";
        // 四舍五入到分
        long temp = Math.round(doubleValue * 100);
        integer = temp / 100;
        fraction = temp % 100;
        jiao = (int) fraction / 10;
        fen = (int) fraction % 10;
        if (jiao == 0 && fen == 0) {
            TailStr = "整";
        } else {
            TailStr = HanDigiStr[jiao];
            if (jiao != 0)
                TailStr += "角";
            if (integer == 0 && jiao == 0) // 零圓後不寫零幾分
                TailStr = "";
            if (fen != 0)
                TailStr += HanDigiStr[fen] + "分";
        }

        return (doubleValue >= 1) ? (SignStr + positiveIntegerToHanString(String.valueOf(integer))
                + "圓" + TailStr) : TailStr;
    }

    /**
     * 輸入BigDecimal型數轉換為大寫中文
     *
     * 精度取決于BigDecimal 的 public double doubleValue() 方法: 是基本收縮轉換。 如果此 BigDecimal
     * 的數量太大而不能表示為 double,則将其适當地轉換為 Double.NEGATIVE_INFINITY 或
     * Double.POSITIVE_INFINITY。 即使在傳回值為有限值的情況下,此轉換也可能丢失關于 BigDecimal 值精度的資訊。
     *
     * @param bigDecimalVal
     * @return 大寫中文
     */
    public static String getChineseMoneyStringForBigDecimal(BigDecimal bigDecimalVal) {
        return getChineseMoneyStringForDoubleVal(bigDecimalVal.doubleValue());
    }

    public static void main(String[] args) {
        System.out.println(getChineseMoneyStringForBigDecimal(new BigDecimal(300).multiply(new BigDecimal(10000))));
    }