Browse Source

金额数字转为大写,修改一千万元时异常情况

master
dimengzhe 3 years ago
parent
commit
f01cf83968
  1. 197
      yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/TransformMoney.java

197
yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/TransformMoney.java

@ -0,0 +1,197 @@
package com.yxt.common.base.utils;
import java.math.BigDecimal;
/**
* @Author dimengzhe
* @Date 2022/11/8 19:10
* @Description
*/
public class TransformMoney {
/*
以下摘自百度百科http://baike.baidu.com/view/359995.htm
大写数字规则
中文大写金额数字应用正楷或行书填写如壹亿等字样不得用一廿或0填写不得自造简化字如果金额数字书写中使用繁体字如贰亿圆的也可
中文大写金额数字到"元"为止的"元"之后应写"整""正""角"之后可以不写"整""正"大写金额数字有"分""分"后面不写"整""正"
中文大写金额数字前应标明"人民币"字样大写金额数字有"分""分"后面不写"整""正"
中文大写金额数字前应标明"人民币"字样大写金额数字应紧接"人民币"字样填写不得留有空白大写金额数字前未印"人民币"字样的应加填"人民币"三字在票据和结算凭证大写金额栏内不得预印固定的"仟、佰、拾、万、仟、佰、拾、元、角、分"字样
阿拉伯数字小写金额数字中有"0"中文大写应按照汉语语言规律金额数字构成和防止涂改的要求进行书写举例如下
阿拉伯数字中间有"0"中文大写要写"零"1409.50应写成人民币壹仟肆佰零玖元伍角
阿拉伯数字中间连续有几个"0"中文大写金额中间可以只写一个"零"6007.14应写成人民币陆仟零柒元壹角肆分
阿拉伯金额数字万位和元位是"0"或者数字中间连续有几个"0"万位元位也是"0"但千位角位不是"0"中文大写金额中可以只写一个零字也可以不写"零"1680.32应写成人民币壹仟陆佰捌拾元零叁角贰分或者写成人民币壹仟陆佰捌拾元叁角贰分又如107000.53应写成人民币壹拾万柒仟元零伍角叁分或者写成人民币壹拾万零柒仟元伍角叁分
阿拉伯金额数字角位是"0"而分位不是"0"中文大写金额"元"后面应写"零"16409.02应写成人民币壹万陆仟肆佰零玖元零贰分又如325.04应写成人民币叁佰贰拾伍元零肆分
*/
static final String big = "零壹贰叁肆伍陆柒捌玖"; //大写
static final String[] units = {"仟佰拾", "角分"}; //单位
/**
* 双精度浮点数转换成字符串
*
* 1如果直接用String.toString(double d)方法超大数额会出现科学计数法的字符串
* 2如果整数部分超过15位数低位部分可能出现误差所以不支持超过15位整数的数值
* 一般数据库设计金额字段时都不会超过15位整数如oracle用Number(18,3)的类型表示整数部分最多15位小数点后保留3位有效数字
*/
public static String getDecimalStr(double d) {
//设置小数点后的精度,保留两位
/*四舍五入结果参考:
0.005,//0.01入
0.015,//0.01舍
0.025,//0.03入
0.035,//0.04入
0.045,//0.04舍
0.055,//0.06入(前一位是5则入)
*/
String str = new BigDecimal(d).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
/*
//经过测试,以下三种方法都是可以用的:
//或1:
String str = new BigDecimal(d).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString();
//或2:
DecimalFormat format = new DecimalFormat();
format.applyPattern("#################0.00");
String str = format.format(d);
//或3:
DecimalFormat decimalFormat = new DecimalFormat();
decimalFormat.setMinimumFractionDigits(2);
decimalFormat.setMaximumFractionDigits(2);
decimalFormat.setGroupingUsed(false);
decimalFormat.setMaximumIntegerDigits(15);
decimalFormat.setMinimumIntegerDigits(15);
str=decimalFormat.format(d);
*/
//如果结果是整数,则去掉尾巴
if (str.endsWith(".00")) {
str = str.replace(".00", "");
}
return str;
}
/**
* 金额是double类型的要先转换成字符串
*
* @param money 金额
*/
public static String transform(double money) {
String moneyStr = getDecimalStr(money);
return transform(moneyStr);
}
/**
* 金额转换成大字
* 我的思路
* 1double数值转换成数值字符串
* 2处理整数部分
* 填充到16位不足16位则前面补'0'然后右起分成四组每组根据"x仟x佰x拾x"的规则转换成大写若该组为"0000"则结果是"零"
* 对这四组结果从高位到低位拼接起来规则[组4][组3]亿[组2][组1]
* 3处理小数部分不多说
*/
public static String transform(String moneyStr) {
String[] parts = moneyStr.split("\\."); //区别整数、小数部分
String result = "";
//处理整数部分
int length = parts[0].length(); //整数部分的位数
if (length > 15) {
return "金额太大,不能处理整数部分超过15位的金额!";
}
String intPart = parts[0];
//填充到16位,因为是分4组,每组4个数字
while (intPart.length() < 16) {
intPart = '0' + intPart;
}
//共分四组,右起四位一组,例如:0001,2003,0030,3400
String[] groups = new String[4];
for (int i = 0; i < groups.length; i++) {
int start = intPart.length() - (i + 1) * 4; //开始位置
int end = intPart.length() - i * 4; //结束位置
groups[i] = intPart.substring(start, end);
groups[i] = transformGroup(groups[i]); //当前组的四位数字转换成大写
}
//对这四组结果从高位到低位拼接起来,规则:[组4]万[组3]亿[组2]万[组1]圆
for (int i = groups.length - 1; i >= 0; i--) {
if (i == 3) { //第四组:万亿级
if (!"零".equals(groups[i])) {
result += groups[i] + "万";
}
} else if (i == 2) { //第三组:亿级
if (!"零".equals(groups[i])) {
result += groups[i] + "亿";
} else {
if (result.length() > 0) {
result += "亿";
}
}
} else if (i == 1) { //第二组:万级
if (!"零".equals(groups[i])) {
result += groups[i] + "万";
} else if (!groups[i].startsWith("零")) {
result += groups[i];
}
} else { //第一组:千级
if (!"零".equals(groups[i]) || result.length() == 0) {
result += groups[i];
}
result += "元";
}
}
if (!"零元".equals(result) && result.startsWith("零")) {
result = result.substring(1, result.length()); //最前面的可能出现的“零”去掉
}
//处理小数部分
if (parts.length == 2) {
String decimalPart = parts[1]; //小数部分
for (int i = 0; i < decimalPart.length(); i++) {
int num = Integer.valueOf(decimalPart.charAt(i) + ""); //提取数字,左起
result += big.charAt(num) + "" + units[1].charAt(i); //数字变大写加上单位
}
result = result.replace("零角", "零"); //去掉"零角"的"角"
result = result.replace("零分", ""); //去掉"零分"
} else {
result += "整"; //没有小数部分,则加上“整”
}
return result;
}
/**
* 处理整数部分的组右起每四位是一组
*
* @param group 四位数字字符串
*/
public static String transformGroup(String group) {
String result = "";
int length = group.length();
for (int i = 0; i < length; i++) {
int digit = Integer.valueOf(group.charAt(i) + ""); //单个数字,左起
String unit = ""; //单位
if (i != length - 1) {
unit = units[0].charAt(i) + "";
}
result += big.charAt(digit) + unit; //数字变大写加上单位
}
result = result.replace("零仟", "零");
result = result.replace("零佰", "零");
result = result.replace("零拾", "零");
while (result.contains("零零")) {
result = result.replace("零零", "零"); //如果有“零零”则变成一个“零”
}
if (!"零".equals(result) && result.endsWith("零")) {
result = result.substring(0, result.length() - 1); //最未尾的可能出现的“零”去掉
}
return result;
}
}
Loading…
Cancel
Save