Java数字金额大写转换

最初(来自CSDN,看到的也是转载贴,未注明出处,侵删)

其实这种工具类网上有很多,但个人感觉这个逻辑更加清晰,所以后面都是在这版的基础是进行修改

public class ConvertNumberToUpper {
    /**
     * 数字金额大写转换,思想先写个完整的然后将如零拾替换成零 要用到正则表达式
     */
    public static String digitUppercase(double n) {
        String fraction[] = {"角", "分"};
        String digit[] = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
        String unit[][] = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}};
        String head = n < 0 ? "负" : "";
        // 如果是负数取绝对值
        n = Math.abs(n);
        // 小数部分
        String s = "";
        for (int i = 0; i < fraction.length; i++) {
            // Math.floor(a)返回大于或等于参数的最小(最接近负无穷大) double值,并等于数学整数,Math.pow(10, i)10的i次幂
            s += (digit[(int)(Math.floor(n * Math.pow(10, i + 1)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
        }
        if (s.length() < 1) {
            s = "整";
        }
        int integerPart = (int)Math.floor(n);
        // 整数部分
        for (int i = 0; i < unit[0].length && integerPart > 0; i++) {
            String p = "";
            for (int j = 0; j < unit[1].length && n > 0; j++) {
                p = digit[integerPart % 10] + unit[1][j] + p;
                integerPart = integerPart / 10;
            }
            s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
        }
        return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
    }
}

自己测试发现能满足业务需要,所以就直接拿来主义了!

后面自己review时发现原贴下面的一条评论是这样的

Math.floor(n * 10 * Math.pow(10, i)) % 10)第一个方法里面,是否会因为double*10精度问题进行取整导致数据不正确? 比如40899.84 * 10的double值408998.39999999…向下取整只会取到3,正好碰到了这个问题

通过mian方法测试发现确实存在这个问题

public static void main(String[] args) {
    // 这里使用System.err与System.out没有区别,只是会用红色字体显示,可以很清晰的看出与日志的区别,强烈建议在测试的时候使用
    System.err.println(digitUppercase(40899.84));
}
输出结果:肆万零捌佰玖拾玖元捌角叁分

原因:Java中浮点类型运算会产生精度问题(二进制浮点运算引起)

尝试解决问题,思路是既然只有小数部分有问题就把小数部分截取后转换成整数处理

public class ConvertNumberToUpper {
    public static String digitCapital(double n) {
        String fraction[] = {"角", "分"};
        String digit[] = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
        String unit[][] = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}};
	
        String head = n < 0 ? "负" : "";
        // 如果是负数取绝对值
        n = Math.abs(n);
        String s = "";
        // 由于n为double类型,所以整数如100转换后变为100.0
        String nStr = n + "";
        // 小数部分,小数点为特殊符号,在分割时需进行转义
        String split = nStr.split("\\.")[1];
		// 如果小数部分只有一位且为0,直接舍弃
        if (!(split.length() == 1 && "0".equals(split))) {
			// 只精确到小数点后两位
            if (split.length() > 2) {
                split = split.substring(0, 2);
            }
            // 将小数部分转换为整数
            Integer integer = Integer.valueOf(split);
            String p = "";
            for (int i = 0; i < split.length() && i < fraction.length; i++) {
                p = digit[integer % 10] + fraction[split.length() - i - 1] + p;
                integer = integer / 10;
            }
            s = p.replaceAll("(零.)+", "") + s;
        }
        if (s.length() < 1) {
            s = "整";
        }
        int integerPart = (int)Math.floor(n);
        // 整数部分
        for (int i = 0; i < unit[0].length && integerPart > 0; i++) {
            String p = "";
            for (int j = 0; j < unit[1].length && n > 0; j++) {
                p = digit[integerPart % 10] + unit[1][j] + p;
                integerPart = integerPart / 10;
            }
            s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
        }
        return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
    }

测试发现解决了上面的问题

然而又发现新的问题

public static void main(String[] args) {
    System.err.println(digitCapital(40800099.84));
}
输出结果:肆仟捌拾万零玖拾玖元捌分

这是因为java中对过大的数据采用科学计数法表示,debug会发现传到方法中的n已经变为4.080009984E7

debug

然后就是解决问题了,思路就是不使用科学计数法表示数据

查资料发现有两种方式实现

// 方法一
NumberFormat nf = NumberFormat.getInstance();
nf.setGroupingUsed(false);
String nStr = nf.format(n);
//方法二
BigDecimal bigDecimal = new BigDecimal(Double.valueOf(n).toString());
String nStr = bigDecimal.toString();

通过下面简单测试,发现方法二的效率明显要好于方法一

public static String digitCapital(double n) {
    String fraction[] = {"角", "分"};
    String digit[] = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
    String unit[][] = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}};

    String head = n < 0 ? "负" : "";
    // 如果是负数取绝对值
    n = Math.abs(n);
    String s = "";
    BigDecimal bigDecimal = new BigDecimal(Double.valueOf(n).toString());
    String nStr = bigDecimal.toString();
    // NumberFormat nf = NumberFormat.getInstance();
    // nf.setGroupingUsed(false);
    // String nStr = nf.format(n);
    // 由于n为double类型,所以整数如100转换后变为100.0
    // 小数部分
    String[] split = nStr.split("\\.");
    if (split.length > 1) {
        // 小数点为特殊符号,在分割时需进行转义
        String decimalStr = split[1];
        if (decimalStr.length() > 2) {
            decimalStr = decimalStr.substring(0, 2);
        }
        // 将小数部分转换为整数
        Integer integer = Integer.valueOf(decimalStr);
        String p = "";
        for (int i = 0; i < decimalStr.length() && i < fraction.length; i++) {
            p = digit[integer % 10] + fraction[decimalStr.length() - i - 1] + p;
            integer = integer / 10;
        }
        s = p.replaceAll("(零.)+", "") + s;
    }
    if (s.length() < 1) {
        s = "整";
    }
    int integerPart = (int)Math.floor(n);
    // 整数部分
    for (int i = 0; i < unit[0].length && integerPart > 0; i++) {
        String p = "";
        for (int j = 0; j < unit[1].length && n > 0; j++) {
            p = digit[integerPart % 10] + unit[1][j] + p;
            integerPart = integerPart / 10;
        }
        s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
    }
    return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
}

public static void main(String[] args) {
    long t1 = System.currentTimeMillis();
    System.err.println(digitCapital(1234340899.011231));
    long t2 = System.currentTimeMillis();
    System.err.println(t2 - t1);
    long t3 = System.currentTimeMillis();
    System.err.println(digitCapital(1234340899.011231));
    long t4 = System.currentTimeMillis();
    System.err.println(t4 - t3);
}

最终版

public static String digitCapital(double n) {
    String fraction[] = {"角", "分"};
    String digit[] = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
    String unit[][] = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}};

    String head = n < 0 ? "负" : "";
    // 如果是负数取绝对值
    n = Math.abs(n);
    String s = "";
    BigDecimal bigDecimal = new BigDecimal(Double.valueOf(n).toString());
    String nStr = bigDecimal.toString();
    // 小数部分
    String[] split = nStr.split("\\.");
    if (split.length > 1) {
        // 小数点为特殊符号,在分割时需进行转义
        String decimalStr = split[1];
        if (decimalStr.length() > 2) {
            decimalStr = decimalStr.substring(0, 2);
        }
        // 将小数部分转换为整数
        Integer integer = Integer.valueOf(decimalStr);
        String p = "";
        for (int i = 0; i < decimalStr.length() && i < fraction.length; i++) {
            p = digit[integer % 10] + fraction[decimalStr.length() - i - 1] + p;
            integer = integer / 10;
        }
        s = p.replaceAll("(零.)+", "") + s;
    }
    if (s.length() < 1) {
        s = "整";
    }
    int integerPart = (int)Math.floor(n);
    // 整数部分
    for (int i = 0; i < unit[0].length && integerPart > 0; i++) {
        String p = "";
        for (int j = 0; j < unit[1].length && n > 0; j++) {
            p = digit[integerPart % 10] + unit[1][j] + p;
            integerPart = integerPart / 10;
        }
        s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
    }
    return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
}

注意:Integer的取值范围是从-2147483648 至 214748364,超过该范围就会按最大值计算

  • 12
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
以下是Java实现大写金额数字的示例代码: ```java public class AmountUtil { private static final String[] CN_UPPER_NUMBER = {"", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"}; private static final String[] CN_UPPER_MONETRAY_UNIT = {"分", "角", "元", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟"}; private static final BigDecimal MAX_VALUE = new BigDecimal("9999999999999.99"); /** * 将大写金额转换数字形式 * * @param amount 大写金额 * @return 数字形式 */ public static BigDecimal convertToNumber(String amount) { if (!amount.matches("^[壹贰叁肆伍陆柒捌玖拾佰仟万亿元角分]*$")) { throw new IllegalArgumentException("不是有效的大写金额格式"); } StringBuilder sb = new StringBuilder(amount); // 处理万、亿 int index = sb.indexOf("亿"); if (index > -1) { String temp = sb.substring(0, index); BigDecimal num = new BigDecimal(convertToNumber(temp).toString()); sb.delete(0, index + 1); sb.insert(0, " "); BigDecimal value = new BigDecimal(convertToNumber(sb.toString().trim()).toString()); return num.multiply(new BigDecimal("100000000")).add(value); } index = sb.indexOf("万"); if (index > -1) { String temp = sb.substring(0, index); BigDecimal num = new BigDecimal(convertToNumber(temp).toString()); sb.delete(0, index + 1); sb.insert(0, " "); BigDecimal value = new BigDecimal(convertToNumber(sb.toString().trim()).toString()); return num.multiply(new BigDecimal("10000")).add(value); } // 处理元、角、分 BigDecimal result = new BigDecimal("0"); int numIndex = 0; int unitIndex = 0; boolean getZero = false; while (numIndex < amount.length()) { char c = amount.charAt(numIndex); if (c >= '壹' && c <= '玖') { int num = c - '壹' + 1; if (unitIndex == 2) { result = result.add(new BigDecimal(num)); } else if (unitIndex == 6) { result = result.add(new BigDecimal(num).multiply(new BigDecimal("10000"))); } else if (unitIndex == 10) { result = result.add(new BigDecimal(num).multiply(new BigDecimal("100000000"))); } else { result = result.add(new BigDecimal(num).multiply(new BigDecimal(Math.pow(10, 3 - unitIndex)))); } getZero = false; } else if (c == '') { getZero = true; } else if (CN_UPPER_MONETRAY_UNIT[unitIndex].equals(String.valueOf(c))) { getZero = false; } else if (c == '元') { getZero = false; } else if (c == '角') { if (getZero) { result = result.add(new BigDecimal("0.1")); } getZero = false; } else if (c == '分') { if (getZero) { result = result.add(new BigDecimal("0.01")); } getZero = false; } if (CN_UPPER_MONETRAY_UNIT[unitIndex].equals(String.valueOf(c))) { ++unitIndex; } ++numIndex; } return result; } public static void main(String[] args) { String amount = "壹亿贰仟叁佰肆拾伍万陆仟柒佰捌拾玖元壹分"; System.out.println(convertToNumber(amount)); // 123456789.01 } } ``` 以上代码可以将大写金额转换数字形式,支持亿、万、元、角、分等单位。注意,该方法只支持中文大写金额格式,不支持阿拉伯数字和英文格式。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值