金额工具类

工具类

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Objects;
import java.util.regex.Pattern;

/**
 * 金额处理工具类
 *
 * @author zql
 * @version 1.0
 * @createTime 2023-05-14 16:31:00
 * @modifyLog
 */
public class MoneyUtil {

    private MoneyUtil() {}

    private static String MODULUS = "10000";
    /**
     * Double类型需要进行格式化,否则会出现科学计数法
     */
    private static DecimalFormat DF = new DecimalFormat("###################.0000000");

    /**
     * 元转万元(默认四舍五入保留6位小数)
     * @param amt
     * @return
     */
    public static BigDecimal toTenThousand(String amt) {
        if (isNotNumber(amt)) {
            return BigDecimal.ZERO;
        }
        return toTenThousand(new BigDecimal(amt));
    }

    /**
     * 元转万元(默认四舍五入保留6位小数)
     * @param amt 不推荐用Double存金额,数值过大会导致精度丢失
     * @return
     */
    public static BigDecimal toTenThousand(Double amt) {
        if (Objects.isNull(amt)) {
            return BigDecimal.ZERO;
        }
        String amtStr = String.valueOf(DF.format(amt));
        return toTenThousand(amtStr);
    }

    /**
     * 元转万元(默认四舍五入保留6位小数)
     * @param amt
     * @return
     */
    public static BigDecimal toTenThousand(BigDecimal amt) {
        return amt.divide(new BigDecimal(MODULUS)).setScale(6, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 万元转元(默认四舍五入保留2位小数)
     * @param amt
     * @return
     */
    public static BigDecimal toTheUnit(String amt) {
        if (isNotNumber(amt)) {
            return BigDecimal.ZERO;
        }
        return toTheUnit(new BigDecimal(amt));
    }

    /**
     * 万元转元(默认四舍五入保留2位小数)
     * @param amt 不推荐用Double存金额,数值过大会导致精度丢失
     * @return
     */
    public static BigDecimal toTheUnit(Double amt) {
        if (Objects.isNull(amt)) {
            return BigDecimal.ZERO;
        }
        String amtStr = String.valueOf(DF.format(amt));
        return toTheUnit(amtStr);
    }

    /**
     * 万元转元(默认四舍五入保留2位小数)
     * @param amt
     * @return
     */
    public static BigDecimal toTheUnit(BigDecimal amt) {
        return amt.multiply(new BigDecimal(MODULUS)).setScale(2, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 数字 + 中文金额转纯金额,单位元(例:500万元,输出结果5000000)
     * @param str
     * @return
     */
    public static BigDecimal getMoney(String str) {
        StringBuffer sb = new StringBuffer();
        if(isNotBlank(str)){
            for(int i = 0; i < str.length(); i++){
                // 46是小数点 (.)
                if(str.charAt(i) >= 48 && str.charAt(i) <= 57 || str.charAt(i) == 46){
                    sb.append(str.charAt(i));
                }
            }
        }
        String res = sb.toString();
        if (isNotBlank(res) && str.contains(UNIT_ARR[7])) {
            return toTheUnit(res);
        }
        if (isNotBlank(res) && str.contains(UNIT_ARR[8])) {
            return new BigDecimal(res).multiply(getUnit(8));
        }
        if (isNotBlank(res)) {
            return new BigDecimal(res);
        }
        return BigDecimal.ZERO;
    }

    /**
     * 对某个数保留小数位数的
     * @author zql
     * @createTime 2020-12-05 16:26:02
     *
     * @param num 某个数
     * @param type 类型,1四舍五入,2五舍六入,3进位处理(就是直接加1),4直接去掉尾数
     * <pre>
     * type = 2,五舍六入时,需要看要求精度后面的第二位(如果存在)是否大于等于5,如果是则会进位
     * </pre>
     * @param count 要保留的小数位数
     * @return 返回double类型的结果
     * <pre>
     * 如果num不是数字时,返回0
     * 如果不处于类型内,则默认四舍五入
     * 如果count小于1时,默认为保留两位小数
     * </pre>
     *
     */
    public static BigDecimal getBigDecimal(String num, int type, int count) {
        if (isNotNumber(num)) {
            return BigDecimal.ZERO;
        }
        if (type < 1 || type > 4) {
            type = 1;
        }
        if (count < 1) {
            count = 2;
        }
        BigDecimal b = new BigDecimal(num);
        BigDecimal r;
        switch (type) {
            case 1:
                // 四舍五入
                r = b.setScale(count, BigDecimal.ROUND_HALF_UP);
                break;
            case 2:
                // 五舍六入,需要看要求精度后面的第二位(如果存在)是否大于等于5,如果是则会进位
                r = b.setScale(count, BigDecimal.ROUND_HALF_DOWN);
                break;
            case 3:
                // 进位处理(就是直接加1)
                r = b.setScale(count, BigDecimal.ROUND_UP);
                break;
            case 4:
                // 直接去掉尾数
                r = b.setScale(count, BigDecimal.ROUND_DOWN);
                break;
            default:
                r = BigDecimal.ZERO;
        }
        return r;
    }

    /**
     * 将大写金额转化为数字金额
     * @author zql
     * @createTime 2020-11-15 21:53:26
     * @version 1.0
     *
     * @param cnStr 大写金额
     * @return
     * @throws Exception
     */
    public static BigDecimal cnToNum(String cnStr) {
        if (isBlank(cnStr)) {
            return BigDecimal.ZERO;
        }
        cnStr = cnStr.replace("元", "圆");
        // 兆级处理
        if (cnStr.indexOf(UNIT_ARR[9]) != -1) {
            return cnToNum1(cnStr);
        } else if (cnStr.indexOf(UNIT_ARR[8]) != -1) {// 亿级处理
            return cnToNum2(cnStr);
        } else if (cnStr.indexOf(UNIT_ARR[7]) != -1) {// 万级处理
            return cnToNum3(cnStr);
        } else {// 低于万级处理
            return cnToNum4(cnStr);
        }
    }

    /**
     * 兆级处理
     * @author zql
     * @createTime 2020-11-15 21:53:26
     * @version 1.0
     *
     * @param cnStr 大写金额
     * @return
     * @throws Exception
     */
    private static BigDecimal cnToNum1(String cnStr) {
        String prefix = cnStr.substring(0, cnStr.indexOf(UNIT_ARR[9]));
        BigDecimal preB = cnToNum4(prefix).multiply(getUnit(9));

        String suffix = cnStr.substring(cnStr.indexOf(UNIT_ARR[9]) + 1, cnStr.length());
        BigDecimal suffB = cnToNum2(suffix);
        return preB.add(suffB);
    }

    /**
     * 亿级处理
     * @author zql
     * @createTime 2020-11-15 21:53:26
     * @version 1.0
     *
     * @param cnStr 大写金额
     * @return
     * @throws Exception
     */
    private static BigDecimal cnToNum2(String cnStr) {
        String prefix = cnStr.substring(0, cnStr.indexOf(UNIT_ARR[8]));
        BigDecimal res = cnToNum4(prefix);
        BigDecimal preB = res.multiply(getUnit(8));

        String suffix = cnStr.substring(cnStr.indexOf(UNIT_ARR[8]) + 1, cnStr.length());
        BigDecimal suffB = cnToNum3(suffix);
        return preB.add(suffB);
    }

    /**
     * 万级处理
     * @author zql
     * @createTime 2020-11-15 21:53:26
     * @version 1.0
     *
     * @param cnStr 大写金额
     * @return
     * @throws Exception
     */
    private static BigDecimal cnToNum3(String cnStr) {
        String prefix = cnStr.substring(0, cnStr.indexOf(UNIT_ARR[7]));
        BigDecimal res = cnToNum4(prefix);
        BigDecimal preB = res.multiply(getUnit(7));

        String suffix = cnStr.substring(cnStr.indexOf(UNIT_ARR[7]) + 1, cnStr.length());
        BigDecimal suffB = cnToNum4(suffix);
        return preB.add(suffB);
    }

    /**
     * 低于万级处理
     * @author zql
     * @createTime 2020-11-15 21:53:26
     * @version 1.0
     *
     * @param cnStr 大写金额
     * @return
     * @throws Exception
     */
    private static BigDecimal cnToNum4(String cnStr) {
        BigDecimal result = BigDecimal.ZERO;
        int lastUnitIndex = 0, num = 0;
        for (int i = 0; i < cnStr.length(); i++) {
            boolean isUnit = true;
            char c = cnStr.charAt(i);
            for (int j = 0; j < NUM_CN.length; j++) {
                // 是数字
                if (c == NUM_CN[j].charAt(0)) {
                    // 数字值 = 索引
                    num = j;
                    isUnit = false;
                    break;
                }
            }
            if (isUnit) {
                // 第一个就是单位,如:拾伍万圆整
                if (i == 0) {
                    num = 1;
                }
                int unitIndex = getUnitIndex(c);
                BigDecimal unit = getUnit(unitIndex);
                // 大写乘单位的结果
                BigDecimal unitSource = new BigDecimal(num).multiply(unit);
                if (unitIndex > lastUnitIndex) {
                    result = result.add(new BigDecimal(num)).multiply(unit);
                } else {
                    result = result.add(unitSource);
                }
                lastUnitIndex = unitIndex;
                num = 0;
            } else if (i == (cnStr.length() - 1)) {// 最后一位处理
                result = result.add(new BigDecimal(num));
            }
        }
        return result.setScale(3, BigDecimal.ROUND_DOWN);
    }

    /**
     * 将数字金额转化为大写金额
     * @author zql
     * @createTime 2020-11-15 21:53:26
     * @version 1.0
     *
     * @param amount
     * @return
     * @throws Exception
     */
    public static String toBigAmt(String amount) throws Exception {
        if (isBlank(amount)) {
            throw new Exception("输入的金额为空!");
        }
        if (isNotNumber(amount)) {
            throw new Exception("输入的金额【" + amount + "】不是数字!" );
        }
        // 四舍五入
        String amt = new BigDecimal(amount).setScale(3, BigDecimal.ROUND_HALF_UP).toString();
        // 取小数位
        String dotPart = "";
        // 取整数位
        String intPart = "";
        // 结果
        String result = null;
        int dotPos;

        if ((dotPos = amt.indexOf(".")) != -1) {
            intPart = amt.substring(0, dotPos);
            dotPart = amt.substring(dotPos + 1);
        } else {
            intPart = amt;
        }
        if (intPart.length() > 16) {
            throw new Exception("金额太大【" + amount + "】,无法转换成大写金额!");
        }
        String intBig = intToBig(intPart);
        String dotBig = dotToBig(dotPart);

        if (dotBig.length() == 0 && intBig.length() != 0) {
            result = intBig + "元整";
        } else if (dotBig.length() == 0 && intBig.length() == 0) {
            result = intBig + "零元";
        } else if (dotBig.length() != 0 && intBig.length() != 0) {
            result = intBig + "元" + dotBig;
        } else {
            result = dotBig;
        }
        return result;
    }

    /**
     * 阿拉伯对应中文
     */
    private static String[] NUM_CN = new String[]{"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
    /**
     * 单位
     */
    private static String[] UNIT_ARR = new String[]{"厘", "分", "角", "圆", "拾", "佰", "仟", "万", "亿", "兆"};

    /**
     * 用来处理整数部分
     * @author zql
     * @createTime 2020-11-15 21:25:44
     * @version 1.0
     *
     * @param intPart
     * @return
     */
    private static String intToBig(String intPart) {
        int grade = 4;
        // 级长
        int gradeLen;

        String result = "";
        String strTmp = "";

        // 得到当前级长
        gradeLen = intPart.length() / grade;
        // 调整级次长度
        if (intPart.length() % grade != 0) {
            gradeLen += 1;
        }
        for (int i = gradeLen; i >= 1; i--) {
            // 取得当前级次数字
            strTmp = getNowGradeVal(intPart, i);
            // 转换大写
            result += getSubUnit(strTmp);
            // 除零 去掉连续的零
            result = dropZero(result);
            // 加级次单位,末位不加单位
            if (i > 1) {
                // 单位不能相连续,连续4个零要特殊处理
                if ("零零零零".equals(getSubUnit(strTmp))) {
                    result += "零";
                } else {
                    result += UNIT_ARR[6 + (i - 1)];
                }
            }
        }
        return result;
    }

    /**
     * 删除“零”
     * @author zql
     * @createTime 2020-11-28 01:31:31
     * @version 1.0
     *
     * @param val
     * @return
     */
    private static String dropZero(String val) {
        // 结果
        String rst;
        // 前一位置字符
        String before;
        // 当前位置字符
        String now;

        before = val.substring(0, 1);
        rst = before;

        for (int i = 1; i < val.length(); i++) {
            now = val.substring(i, i + 1);
            // 不同时为零
            if (!("零".equals(now) && "零".equals(before))) {
                rst += now;
            }
            before = now;
        }
        // 结果长度
        int rstLen = rst.length();
        // 末位去零
        if ("零".equals(rst.substring(rstLen - 1, rstLen))) {
            rst = rst.substring(0, rstLen - 1);
        }
        return rst;
    }
    /**
     * 用来处理小数部分
     * @author zql
     * @createTime 2020-11-15 21:34:39
     * @version 1.0
     *
     * @param dotPart
     * @return
     */
    private static String dotToBig(String dotPart) {
        String ret = "";
        for (int i = 0; i < dotPart.length() && i < 3; i++) {
            int n;
            if ((n = Integer.parseInt(dotPart.substring(i, i + 1))) != 0) {
                ret += NUM_CN[n] + UNIT_ARR[2 - i];
            }
        }
        return ret;
    }

    /**
     * 数值转换
     * @author zql
     * @createTime 2021-01-03 03:09:06
     *
     * @param val
     * @return
     * @throws
     */
    private static String getSubUnit(String val) {
        String rst = "";
        int valLen = val.length();

        for (int i = 0; i < valLen; i++) {
            String s = val.substring(i, i + 1);
            int n = Integer.parseInt(s);
            // “零”作特殊处理,转换后数末不能为零
            if (n == 0 && i != valLen - 1) {
                rst += "零";
            } else {
                rst += NUM_CN[n];
                // 个位不加单位
                if (i != valLen - 1) {
                    rst += UNIT_ARR[6 - (i + 4 - valLen)];
                }
            }
        }
        return rst;
    }

    /**
     * 得到当前级次的字符串
     * @author zql
     * @createTime 2021-01-03 03:09:47
     *
     * @param val
     * @param grade
     * @return
     * @throws
     */
    private static String getNowGradeVal(String val, int grade) {
        int curGrade = 4;
        String rst;
        int valLen = val.length();
        if (valLen <= grade * curGrade) {
            rst = val.substring(0, valLen - (grade - 1) * curGrade);
        } else {
            rst = val.substring(valLen - grade * curGrade, valLen - (grade - 1) * curGrade);
        }
        return rst;
    }

    /**
     * 获取单位索引
     * @param c
     * @return
     */
    private static int getUnitIndex(char c) {
        for (int j = 0; j < UNIT_ARR.length; j++) {
            if (c == UNIT_ARR[j].charAt(0)) {
                return j;
            }
        }
        return 0;
    }

    /**
     * 获取单位金额
     * @param unitIndex 单位索引
     * @return
     */
    private static BigDecimal getUnit(int unitIndex) {
        String num = "0";
        switch (unitIndex) {
            // '厘', '分', '角', '圆', '拾', '佰', '仟', '万', '亿', '兆'
            case 0:
                num = "0.001";
                break;
            case 1:
                num = "0.01";
                break;
            case 2:
                num = "0.1";
                break;
            case 3:
                num = "1";
                break;
            case 4:
                num = "10";
                break;
            case 5:
                num = "100";
                break;
            case 6:
                num = "1000";
                break;
            case 7:
                num = "10000";
                break;
            case 8:
                num = "100000000";
                break;
            case 9:
                num = "1000000000000";
                break;
            default:
                break;
        }
        return new BigDecimal(num);
    }

    private static String REGEX_NUMBER_1 = "[-\\+]{0,1}0|^\\+{0,1}[1-9]\\d*|^-[1-9]\\d*";
    private static String REGEX_NUMBER_2 = "[-\\+]{0,1}\\d{1}\\.\\d+|[-\\+]{0,1}[1-9]{1}\\d*\\.\\d+";
    /**
     * 判断字符串是否不是数字
     * @author zql
     * @createTime 2020-12-05 16:31:34
     *
     * @param str
     * @return 不是数字返回true,是数字返回false
     */
    private static boolean isNotNumber(String str) {
        return !isNumber(str);
    }

    /**
     * 判断字符串是否是数字
     * @author zql
     * @createTime 2020-12-05 16:31:34
     *
     * @param str
     * <pre>
     * 小数点后都是0会判断成不是数字,例如:0.00返回的是false
     * </pre>
     * @return 是数字返回true,否则返回false
     */
    private static boolean isNumber(String str) {
        return isMatch(REGEX_NUMBER_1, str) || isMatch(REGEX_NUMBER_2, str);
    }

    /**
     * 是否和正则表达式匹配
     * @author zql
     * @createTime 2020-12-05 16:27:39
     *
     * @param regex 正则表达式
     * @param matchStr 要匹配的字符串
     * @return 匹配成功返回true,否则返回false;
     */
    private static boolean isMatch(String regex, String matchStr) {
        if (Objects.isNull(matchStr) || matchStr.trim().length() == 0) {
            return false;
        }
        Pattern pattern = Pattern.compile(regex);
        return pattern.matcher(matchStr).matches();
    }


    /**
     * 检查一个字符串是否为空、""或null。
     * <pre>
     * StringUtil.isBlank(null)      = true
     * StringUtil.isBlank("")        = true
     * StringUtil.isBlank(" ")       = true
     * StringUtil.isBlank("bob")     = false
     * StringUtil.isBlank("  bob  ") = false
     * </pre>
     *
     * @param str
     * @return
     */
    public static boolean isBlank(String str) {
        int strLen;
        if (Objects.isNull(str) || (strLen = str.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if ((Character.isWhitespace(str.charAt(i)) == false)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 检查一个字符串是否不为空、不为""或不为null。
     * <pre>
     * StringUtil.isNotBlank(null)      = false
     * StringUtil.isNotBlank("")        = false
     * StringUtil.isNotBlank(" ")       = false
     * StringUtil.isNotBlank("bob")     = true
     * StringUtil.isNotBlank("  bob  ") = true
     * </pre>
     *
     * @param str
     * @return
     */
    public static boolean isNotBlank(String str) {
        return !isBlank(str);
    }

}

测试类

import org.junit.Test;
import top.zqlweb.util.tool.MoneyUtil;

import java.math.BigDecimal;

public class MoneyUtilTest {

    @Test
    public void toBigAmtAndCnToNumTest() throws Exception {
        String s0 = "0.00";
        String t0 = MoneyUtil.toBigAmt(s0);
        System.out.println(s0 + "=" + t0);
        System.out.println(MoneyUtil.cnToNum(t0) + "=" + t0);
        System.out.println();

        String s1 = "1314.7408";
        String t1 = MoneyUtil.toBigAmt(s1);
        System.out.println(s1 + "=" + t1);
        System.out.println(MoneyUtil.cnToNum(t1) + "=" + t1);
        System.out.println();

        String s2 = "1004.7488";
        String t2 = MoneyUtil.toBigAmt(s2);
        System.out.println(s2 + "=" + t2);
        System.out.println(MoneyUtil.cnToNum(t2) + "=" + t2);
        System.out.println();

        String s3 = "5201314";
        String t3 = MoneyUtil.toBigAmt(s3);
        System.out.println(s3 + "=" + t3);
        System.out.println(MoneyUtil.cnToNum(t3) + "=" + t3);
        System.out.println();

        String s4 = "100145201314.7";
        String t4 = MoneyUtil.toBigAmt(s4);
        System.out.println(s4 + "=" + t4);
        System.out.println(MoneyUtil.cnToNum(t4) + "=" + t4);
        System.out.println();

        String s5 = "9765412345201300.0408";
        String t5 = MoneyUtil.toBigAmt(s5);
        System.out.println(s5 + "=" + t5);
        System.out.println(MoneyUtil.cnToNum(t5) + "=" + t5);
        System.out.println();

        String s6 = "9000002345201314.7";
        String t6 = MoneyUtil.toBigAmt(s6);
        System.out.println(s6 + "=" + t6);
        System.out.println(MoneyUtil.cnToNum(t6) + "=" + t6);
        System.out.println();

        String s7 = "9000002005201000.7408";
        String t7 = MoneyUtil.toBigAmt(s7);
        System.out.println(s7 + "=" + t7);
        System.out.println(MoneyUtil.cnToNum(t7) + "=" + t7);
        System.out.println();

        String s8 = "10202209.01";
        String t8 = MoneyUtil.toBigAmt(s8);
        System.out.println(s8 + "=" + t8);
        System.out.println(MoneyUtil.cnToNum(t8) + "=" + t8);
        System.out.println();

        String s9 = "10200209.01";
        String t9 = MoneyUtil.toBigAmt(s9);
        System.out.println(s9 + "=" + t9);
        System.out.println(MoneyUtil.cnToNum(t9) + "=" + t9);
        System.out.println();


        String e = "19000002345201314.7408";
        System.out.println(e + "=" + MoneyUtil.toBigAmt(e));
    }

    @Test
    public void toTenThousandTest() throws Exception {
        String s11 = "10202209.01";
        System.out.println("11=" + MoneyUtil.toTenThousand(s11));
        String s12 = "1020.220901";
        System.out.println("12=" + MoneyUtil.toTheUnit(s12));

        Double s21 = 876543211.12;
        System.out.println("21=" + MoneyUtil.toTenThousand(s21));
        Double s22 = 87654.321112;
        System.out.println("22=" + MoneyUtil.toTheUnit(s22));

        BigDecimal b1 = new BigDecimal("19000002345201314.7408");
        System.out.println("b1=" + MoneyUtil.toTenThousand(b1));
        BigDecimal b2 = new BigDecimal("1900000234520.13147408");
        System.out.println("b2=" + MoneyUtil.toTheUnit(b2));
    }

    @Test
    public void getMoneyTest() {
        String s1 = null;
        System.out.println(s1 + "=" + MoneyUtil.getMoney(s1));

        String s2 = " 5 0.1234567 万 元";
        System.out.println(s2 + "=" + MoneyUtil.getMoney(s2));

        String s3 = "5000元";
        System.out.println(s3 + "=" + MoneyUtil.getMoney(s3));

        String s4 = " 500万元";
        System.out.println(s4 + "=" + MoneyUtil.getMoney(s4));

        String s5 = " 1.2 5万元";
        System.out.println(s5 + "=" + MoneyUtil.getMoney(s5));

        String s6 = " 1.2 5亿元";
        System.out.println(s6 + "=" + MoneyUtil.getMoney(s6));

    }

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值