@TOC
在遇到相关需求,需要将金额转成中文大写, 此前遇到类似,都是前端进行转换,故整理记录一下后端实现.
1 自定义实现方案
/**
* 把输入的金额转换为汉语中人民币的大写
*/
public class NumberToCN {
// 大写数字
private static final String[] NUMBERS = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
// 整数部分的单位
private static final String[] IUNIT = {"元", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟", "万", "拾", "佰", "仟"};
// 小数部分的单位
private static final String[] DUNIT = {"角", "分", "厘"};
/**
* 转换为大写的中文金额
*
* @param str 字符串类型的 金额数字
* @return
*/
public static String toChinese(String str) {
// 判断输入的金额字符串是否符合要求
if (StrUtil.isBlank(str) || !str.matches("(-)?[\\d]*(.)?[\\d]*")) {
return "错误金额";
}
if ("0".equals(str) || "0.00".equals(str) || "0.0".equals(str)) {
return "零元";
}
// 判断金额数字中是否存在负号"-"
boolean flag = false;
if (str.startsWith("-")) {
// 标志位,标志此金额数字为负数
flag = true;
str = str.replaceAll("-", "");
}
// 去掉金额数字中的逗号","
str = str.replaceAll(",", "");
String integerStr;//整数部分数字
String decimalStr;//小数部分数字
// 初始化:分离整数部分和小数部分
if (str.indexOf(".") > 0) {
integerStr = str.substring(0, str.indexOf("."));
decimalStr = str.substring(str.indexOf(".") + 1);
} else if (str.indexOf(".") == 0) {
integerStr = "";
decimalStr = str.substring(1);
} else {
integerStr = str;
decimalStr = "";
}
// beyond超出计算能力,直接返回
if (integerStr.length() > IUNIT.length) {
return "超出计算能力!";
}
// 整数部分数字
int[] integers = toIntArray(integerStr);
// 判断整数部分是否存在输入012的情况
if (integers.length > 1 && integers[0] == 0) {
return "抱歉,输入数字不符合要求!";
}
// 设置万单位
boolean isWan = isWan5(integerStr);
// 小数部分数字
int[] decimals = toIntArray(decimalStr);
// 返回最终的大写金额
String result = getChineseInteger(integers, isWan) + getChineseDecimal(decimals);
if (flag) {
// 如果是负数,加上"负"
return "负" + result;
} else {
return result;
}
}
/**
* 将字符串转为int数组
*
* @param number 数字
* @return
*/
private static int[] toIntArray(String number) {
int[] array = new int[number.length()];
for (int i = 0; i < number.length(); i++) {
array[i] = Integer.parseInt(number.substring(i, i + 1));
}
return array;
}
/**
* 将整数部分转为大写的金额
*
* @param integers 整数部分数字
* @param isWan 整数部分是否已经是达到【万】
* @return
*/
public static String getChineseInteger(int[] integers, boolean isWan) {
StringBuffer chineseInteger = new StringBuffer("");
int length = integers.length;
if (length == 1 && integers[0] == 0) {
return "";
}
for (int i = 0; i < length; i++) {
String key = "";
if (integers[i] == 0) {
if ((length - i) == 13)//万(亿)
key = IUNIT[4];
else if ((length - i) == 9) {//亿
key = IUNIT[8];
} else if ((length - i) == 5 && isWan) {//万
key = IUNIT[4];
} else if ((length - i) == 1) {//元
key = IUNIT[0];
}
if ((length - i) > 1 && integers[i + 1] != 0) {
key += NUMBERS[0];
}
}
chineseInteger.append(integers[i] == 0 ? key : (NUMBERS[integers[i]] + IUNIT[length - i - 1]));
}
return chineseInteger.toString();
}
/**
* 将小数部分转为大写的金额
*
* @param decimals 小数部分的数字
* @return
*/
private static String getChineseDecimal(int[] decimals) {
StringBuffer chineseDecimal = new StringBuffer("");
for (int i = 0; i < decimals.length; i++) {
if (i == 3) {
break;
}
chineseDecimal.append(decimals[i] == 0 ? "" : (NUMBERS[decimals[i]] + DUNIT[i]));
}
return chineseDecimal.toString();
}
/**
* 判断当前整数部分是否已经是达到【万】
*
* @param integerStr 整数部分数字
* @return
*/
private static boolean isWan5(String integerStr) {
int length = integerStr.length();
if (length > 4) {
String subInteger = "";
if (length > 8) {
subInteger = integerStr.substring(length - 8, length - 4);
} else {
subInteger = integerStr.substring(0, length - 4);
}
return Integer.parseInt(subInteger) > 0;
} else {
return false;
}
}
public static void main(String[] args) {
String number = "125555437.01";
System.out.println(number + ": " + ConvertUpMoney.toChinese(number));
// 125555437.01: 壹亿贰仟伍佰伍拾伍万伍仟肆佰叁拾柒元壹分
number = "1234567890563886.123";
System.out.println(number+": "+ConvertUpMoney.toChinese(number));
// 1234567890563886.123: 壹仟贰佰叁拾肆万伍仟陆佰柒拾捌亿玖仟零伍拾陆万叁仟捌佰捌拾陆元壹角贰分叁厘
}
}
2 工具类(hutool)
NumberChineseFormatter#format()是hutool工具包中提供的方法,可以将数字金额转成大写汉字.此外, hutool包中,也提供了中文大写转金额数字的方法chineseToNumber.
/**
* 把输入的金额转换为汉语中人民币的大写
*/
public class NumberToCN {
public static void main(String[] args) {
List<Number> numbers = Arrays.asList(4, 100, 238948855.55,100.03);
System.out.println("数字转金额:");
numbers.forEach(item -> {
System.out.println(NumberChineseFormatter.format(item.doubleValue(), true, true));
});
/**
肆元整
壹佰元整
贰亿叁仟捌佰玖拾肆万捌仟捌佰伍拾伍元伍角伍分
壹佰元零叁分
*/
}
}
3 自定义兼容外币转换
在某些特殊的场景, 需要将外币种转为中文大写,如100.10,币种美元, 可转为100美元10美分, 且金额都为大写中文. 结合hutool工具类,添加自定义转换方法.
/**
* 把输入的金额转换为汉语中人民币的大写
*/
public class NumberToCN {
// 美元 美分
private static final String[] MEIYUAN = {"美元", "美分"};
// 英镑 便士
private static final String[] BANG = {"英镑", "便士"};
// 法郎 生丁
private static final String[] FALANG = {"法郎", "生丁"};
// 克朗 欧尔
private static final String[] KELANG = {"克朗", "欧尔"};
// 欧元 欧分
private static final String[] OUYUAN = {"欧元", "欧分"};
private static Map<String,String[]> stringMap = new HashMap<>();
public enum MoneyEnum{
OUYUAN("35","欧元"),
MEYUAN("32","美元"),
BANG("43","英镑"),
KELANG_DANMAI("85","克朗_丹麦"),
KELANG_RUIDIAN("88","克朗_瑞典"),
FALANG("87","法朗"),
;
MoneyEnum() {
}
MoneyEnum(String code, String name) {
this.code = code;
this.name = name;
}
// 币种编号
private String code;
// 币种名称
private String name;
public String getName() {
return name;
}
public String getCode() {
return code;
}
public static MoneyEnum getMoneyEnum(String ccyNbr){
for (MoneyEnum value : values()) {
if (value.code.equals(ccyNbr)){
return value;
}
}
return null;
}
}
static {
stringMap.put(MoneyEnum.OUYUAN.getCode(),OUYUAN);
stringMap.put(MoneyEnum.BANG.getCode(),BANG);
stringMap.put(MoneyEnum.MEYUAN.getCode(),MEIYUAN);
stringMap.put(MoneyEnum.KELANG_DANMAI.getCode(),KELANG);
stringMap.put(MoneyEnum.KELANG_RUIDIAN.getCode(),KELANG);
stringMap.put(MoneyEnum.FALANG.getCode(),FALANG);
}
/**
* 将金额转成大写金额
*
* @param money 金额
* @param ccyNbr 币种
* @return
*/
private static String moneyToUpper(String money, String ccyNbr) {
// 默认使用人民币 转换
String result = "";
// 如果是外币, 则调用自定义方法
if (stringMap.keySet().contains(ccyNbr)) {
result = getUpperString(money, ccyNbr);
}else{
// 默认按照人民币处理
double qian = Double.parseDouble(money);
result = NumberChineseFormatter.format(qian, true, true);
}
return result;
}
private static String getUpperString(String money, String ccyNbr) {
String result = "";
double qian = Double.parseDouble(money);
// 拆分整数部分 小数部分
String[] split = money.split("\\.");
if(1 == split.length){
// 只有整数部分
result = NumberChineseFormatter.format(qian, true, true);
result= result.replace("元",stringMap.get(ccyNbr)[0]);
}else if (2 == split.length){
// 整数部分
String s1 = split[0];
// 小数部分
String s2 = split[1];
// 处理整数部分
double mon3 = Double.parseDouble(s1);
s1 = NumberChineseFormatter.format(mon3, true, true);
s1 = s1.replace("元整",stringMap.get(ccyNbr)[0]);
// 处理小数部分
if ("00".equals(s2) || "0".equals(s2)){
// 小数部分为0 不用翻译处理 加个整字
s2 = "整";
}else {
double mon4 = Double.parseDouble(s2);
s2 = NumberChineseFormatter.format(mon4, true, true);
s2 = s2.replace("元整",stringMap.get(ccyNbr)[1]);
}
result = s1+s2;
}
return result;
}
public static void main(String[] args) {
System.out.println(moneyToUpper("100.12", "35"));
System.out.println(moneyToUpper("100.12", "43"));
System.out.println(moneyToUpper("100.12", "32"));
System.out.println(moneyToUpper("100.12", "85"));
System.out.println(moneyToUpper("100.12", "87"));
// 壹佰欧元壹拾贰欧分
// 壹佰英镑壹拾贰便士
// 壹佰美元壹拾贰美分
// 壹佰克朗壹拾贰欧尔
// 壹佰法郎壹拾贰生丁
}
}
4 总结
关于金额数字转大写汉字, 功能还是比较常见, 但是涉及到外币的转换还是少见, 需要自己包装加判断实现. 此前,也没有遇到更好的处理办法,后续遇到再追加补充.