diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/TransformMoney.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/TransformMoney.java new file mode 100644 index 0000000..b736ddf --- /dev/null +++ b/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); + } + + /** + * 金额转换成大字 + * 我的思路: + * 1、double数值转换成数值字符串 + * 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; + } + +}