mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
fix code
This commit is contained in:
@@ -20,7 +20,8 @@ import org.dromara.hutool.core.convert.impl.EnumConverter;
|
|||||||
import org.dromara.hutool.core.convert.impl.MapConverter;
|
import org.dromara.hutool.core.convert.impl.MapConverter;
|
||||||
import org.dromara.hutool.core.lang.Assert;
|
import org.dromara.hutool.core.lang.Assert;
|
||||||
import org.dromara.hutool.core.math.ChineseNumberFormatter;
|
import org.dromara.hutool.core.math.ChineseNumberFormatter;
|
||||||
import org.dromara.hutool.core.math.NumberWordFormatter;
|
import org.dromara.hutool.core.math.ChineseNumberParser;
|
||||||
|
import org.dromara.hutool.core.math.EnglishNumberFormatter;
|
||||||
import org.dromara.hutool.core.reflect.TypeReference;
|
import org.dromara.hutool.core.reflect.TypeReference;
|
||||||
import org.dromara.hutool.core.text.StrUtil;
|
import org.dromara.hutool.core.text.StrUtil;
|
||||||
import org.dromara.hutool.core.text.UnicodeUtil;
|
import org.dromara.hutool.core.text.UnicodeUtil;
|
||||||
@@ -1003,7 +1004,7 @@ public class Convert {
|
|||||||
* @since 3.0.9
|
* @since 3.0.9
|
||||||
*/
|
*/
|
||||||
public static String numberToWord(final Number number) {
|
public static String numberToWord(final Number number) {
|
||||||
return NumberWordFormatter.format(number);
|
return EnglishNumberFormatter.format(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1018,7 +1019,7 @@ public class Convert {
|
|||||||
* @since 5.5.9
|
* @since 5.5.9
|
||||||
*/
|
*/
|
||||||
public static String numberToSimple(final Number number) {
|
public static String numberToSimple(final Number number) {
|
||||||
return NumberWordFormatter.formatSimple(number.longValue());
|
return EnglishNumberFormatter.formatSimple(number.longValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1047,7 +1048,7 @@ public class Convert {
|
|||||||
* @since 5.6.0
|
* @since 5.6.0
|
||||||
*/
|
*/
|
||||||
public static int chineseToNumber(final String number){
|
public static int chineseToNumber(final String number){
|
||||||
return ChineseNumberFormatter.parseFromChinese(number);
|
return ChineseNumberParser.parseFromChineseNumber(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1078,7 +1079,7 @@ public class Convert {
|
|||||||
* @since 5.8.5
|
* @since 5.8.5
|
||||||
*/
|
*/
|
||||||
public static BigDecimal chineseMoneyToNumber(final String chineseMoneyAmount){
|
public static BigDecimal chineseMoneyToNumber(final String chineseMoneyAmount){
|
||||||
return ChineseNumberFormatter.parseFromChineseMoney(chineseMoneyAmount);
|
return ChineseNumberParser.parseFromChineseMoney(chineseMoneyAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------- 数字转换
|
// -------------------------------------------------------------------------- 数字转换
|
||||||
|
@@ -14,10 +14,6 @@ package org.dromara.hutool.core.math;
|
|||||||
|
|
||||||
import org.dromara.hutool.core.lang.Assert;
|
import org.dromara.hutool.core.lang.Assert;
|
||||||
import org.dromara.hutool.core.text.StrUtil;
|
import org.dromara.hutool.core.text.StrUtil;
|
||||||
import org.dromara.hutool.core.array.ArrayUtil;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.RoundingMode;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数字转中文类<br>
|
* 数字转中文类<br>
|
||||||
@@ -68,155 +64,6 @@ public class ChineseNumberFormatter {
|
|||||||
return numberToChinese(c - '0', isUseTraditional);
|
return numberToChinese(c - '0', isUseTraditional);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 把中文转换为数字 如 二百二十 220<br>
|
|
||||||
* <ul>
|
|
||||||
* <li>一百一十二 -》 112</li>
|
|
||||||
* <li>一千零一十二 -》 1012</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param chinese 中文字符
|
|
||||||
* @return 数字
|
|
||||||
* @since 5.6.0
|
|
||||||
*/
|
|
||||||
public static int parseFromChinese(final String chinese) {
|
|
||||||
final int length = chinese.length();
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
// 节总和
|
|
||||||
int section = 0;
|
|
||||||
int number = 0;
|
|
||||||
ChineseUnit unit = null;
|
|
||||||
char c;
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
c = chinese.charAt(i);
|
|
||||||
final int num = parseFromChinese(c);
|
|
||||||
if (num >= 0) {
|
|
||||||
if (num == 0) {
|
|
||||||
// 遇到零时节结束,权位失效,比如两万二零一十
|
|
||||||
if (number > 0 && null != unit) {
|
|
||||||
section += number * (unit.value / 10);
|
|
||||||
}
|
|
||||||
unit = null;
|
|
||||||
} else if (number > 0) {
|
|
||||||
// 多个数字同时出现,报错
|
|
||||||
throw new IllegalArgumentException(StrUtil.format("Bad number '{}{}' at: {}", chinese.charAt(i - 1), c, i));
|
|
||||||
}
|
|
||||||
// 普通数字
|
|
||||||
number = num;
|
|
||||||
} else {
|
|
||||||
unit = chineseToUnit(c);
|
|
||||||
if (null == unit) {
|
|
||||||
// 出现非法字符
|
|
||||||
throw new IllegalArgumentException(StrUtil.format("Unknown unit '{}' at: {}", c, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
//单位
|
|
||||||
if (unit.secUnit) {
|
|
||||||
// 节单位,按照节求和
|
|
||||||
section = (section + number) * unit.value;
|
|
||||||
result += section;
|
|
||||||
section = 0;
|
|
||||||
} else {
|
|
||||||
// 非节单位,和单位前的单数字组合为值
|
|
||||||
int unitNumber = number;
|
|
||||||
if (0 == number && 0 == i) {
|
|
||||||
// issue#1726,对于单位开头的数组,默认赋予1
|
|
||||||
// 十二 -> 一十二
|
|
||||||
// 百二 -> 一百二
|
|
||||||
unitNumber = 1;
|
|
||||||
}
|
|
||||||
section += (unitNumber * unit.value);
|
|
||||||
}
|
|
||||||
number = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (number > 0 && null != unit) {
|
|
||||||
number = number * (unit.value / 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result + section + number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 中文大写数字金额转换为数字,返回结果以元为单位的BigDecimal类型数字<br>
|
|
||||||
* 如:
|
|
||||||
* “陆万柒仟伍佰伍拾陆元叁角贰分”返回“67556.32”
|
|
||||||
* “叁角贰分”返回“0.32”
|
|
||||||
*
|
|
||||||
* @param chineseMoneyAmount 中文大写数字金额
|
|
||||||
* @return 返回结果以元为单位的BigDecimal类型数字
|
|
||||||
*/
|
|
||||||
public static BigDecimal parseFromChineseMoney(final String chineseMoneyAmount) {
|
|
||||||
if (StrUtil.isBlank(chineseMoneyAmount)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
int yi = chineseMoneyAmount.indexOf("元");
|
|
||||||
if (yi == -1) {
|
|
||||||
yi = chineseMoneyAmount.indexOf("圆");
|
|
||||||
}
|
|
||||||
final int ji = chineseMoneyAmount.indexOf("角");
|
|
||||||
final int fi = chineseMoneyAmount.indexOf("分");
|
|
||||||
|
|
||||||
// 先找到单位为元的数字
|
|
||||||
String yStr = null;
|
|
||||||
if (yi > 0) {
|
|
||||||
yStr = chineseMoneyAmount.substring(0, yi);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 再找到单位为角的数字
|
|
||||||
String jStr = null;
|
|
||||||
if (ji > 0) {
|
|
||||||
if (yi >= 0) {
|
|
||||||
//前面有元,角肯定要在元后面
|
|
||||||
if (ji > yi) {
|
|
||||||
jStr = chineseMoneyAmount.substring(yi + 1, ji);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//没有元,只有角
|
|
||||||
jStr = chineseMoneyAmount.substring(0, ji);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 再找到单位为分的数字
|
|
||||||
String fStr = null;
|
|
||||||
if (fi > 0) {
|
|
||||||
if (ji >= 0) {
|
|
||||||
//有角,分肯定在角后面
|
|
||||||
if (fi > ji) {
|
|
||||||
fStr = chineseMoneyAmount.substring(ji + 1, fi);
|
|
||||||
}
|
|
||||||
} else if (yi > 0) {
|
|
||||||
//没有角,有元,那就坐元后面找
|
|
||||||
if (fi > yi) {
|
|
||||||
fStr = chineseMoneyAmount.substring(yi + 1, fi);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//没有元、角,只有分
|
|
||||||
fStr = chineseMoneyAmount.substring(0, fi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//元、角、分
|
|
||||||
int y = 0, j = 0, f = 0;
|
|
||||||
if (StrUtil.isNotBlank(yStr)) {
|
|
||||||
y = ChineseNumberFormatter.parseFromChinese(yStr);
|
|
||||||
}
|
|
||||||
if (StrUtil.isNotBlank(jStr)) {
|
|
||||||
j = ChineseNumberFormatter.parseFromChinese(jStr);
|
|
||||||
}
|
|
||||||
if (StrUtil.isNotBlank(fStr)) {
|
|
||||||
f = ChineseNumberFormatter.parseFromChinese(fStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
BigDecimal amount = new BigDecimal(y);
|
|
||||||
amount = amount.add(BigDecimal.valueOf(j).divide(BigDecimal.TEN, 2, RoundingMode.HALF_UP));
|
|
||||||
amount = amount.add(BigDecimal.valueOf(f).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
|
|
||||||
return amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 NumberChineseFormatter 默认对象
|
* 获取 NumberChineseFormatter 默认对象
|
||||||
*
|
*
|
||||||
@@ -230,24 +77,9 @@ public class ChineseNumberFormatter {
|
|||||||
* 中文形式,奇数位置是简体,偶数位置是记账繁体,0共用<br>
|
* 中文形式,奇数位置是简体,偶数位置是记账繁体,0共用<br>
|
||||||
* 使用混合数组提高效率和数组复用
|
* 使用混合数组提高效率和数组复用
|
||||||
**/
|
**/
|
||||||
private static final char[] DIGITS = {'零', '一', '壹', '二', '贰', '三', '叁', '四', '肆', '五', '伍',
|
static final char[] DIGITS = {'零', '一', '壹', '二', '贰', '三', '叁', '四', '肆', '五', '伍',
|
||||||
'六', '陆', '七', '柒', '八', '捌', '九', '玖'};
|
'六', '陆', '七', '柒', '八', '捌', '九', '玖'};
|
||||||
|
|
||||||
/**
|
|
||||||
* 汉字转阿拉伯数字的
|
|
||||||
*/
|
|
||||||
private static final ChineseUnit[] CHINESE_NAME_VALUE = {
|
|
||||||
new ChineseUnit(' ', 1, false),
|
|
||||||
new ChineseUnit('十', 10, false),
|
|
||||||
new ChineseUnit('拾', 10, false),
|
|
||||||
new ChineseUnit('百', 100, false),
|
|
||||||
new ChineseUnit('佰', 100, false),
|
|
||||||
new ChineseUnit('千', 1000, false),
|
|
||||||
new ChineseUnit('仟', 1000, false),
|
|
||||||
new ChineseUnit('万', 1_0000, true),
|
|
||||||
new ChineseUnit('亿', 1_0000_0000, true),
|
|
||||||
};
|
|
||||||
|
|
||||||
// region ----- 配置项
|
// region ----- 配置项
|
||||||
private boolean useTraditional;
|
private boolean useTraditional;
|
||||||
private boolean moneyMode;
|
private boolean moneyMode;
|
||||||
@@ -514,7 +346,7 @@ public class ChineseNumberFormatter {
|
|||||||
lastIsZero = true;
|
lastIsZero = true;
|
||||||
} else { // 取到的数字不是 0
|
} else { // 取到的数字不是 0
|
||||||
final boolean isUseTraditional = this.useTraditional;
|
final boolean isUseTraditional = this.useTraditional;
|
||||||
chineseStr.insert(0, numberToChinese(digit, isUseTraditional) + getUnitName(i, isUseTraditional));
|
chineseStr.insert(0, numberToChinese(digit, isUseTraditional) + ChineseNumberParser.getUnitName(i, isUseTraditional));
|
||||||
lastIsZero = false;
|
lastIsZero = false;
|
||||||
}
|
}
|
||||||
temp = temp / 10;
|
temp = temp / 10;
|
||||||
@@ -522,40 +354,6 @@ public class ChineseNumberFormatter {
|
|||||||
return chineseStr.toString();
|
return chineseStr.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 查找对应的权对象
|
|
||||||
*
|
|
||||||
* @param chinese 中文权位名
|
|
||||||
* @return 权对象
|
|
||||||
*/
|
|
||||||
private static ChineseUnit chineseToUnit(final char chinese) {
|
|
||||||
for (final ChineseUnit chineseNameValue : CHINESE_NAME_VALUE) {
|
|
||||||
if (chineseNameValue.name == chinese) {
|
|
||||||
return chineseNameValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将汉字单个数字转换为int类型数字
|
|
||||||
*
|
|
||||||
* @param chinese 汉字数字,支持简体和繁体
|
|
||||||
* @return 数字,-1表示未找到
|
|
||||||
* @since 5.6.4
|
|
||||||
*/
|
|
||||||
private static int parseFromChinese(char chinese) {
|
|
||||||
if ('两' == chinese) {
|
|
||||||
// 口语纠正
|
|
||||||
chinese = '二';
|
|
||||||
}
|
|
||||||
final int i = ArrayUtil.indexOf(DIGITS, chinese);
|
|
||||||
if (i > 0) {
|
|
||||||
return (i + 1) / 2;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单个数字转汉字
|
* 单个数字转汉字
|
||||||
*
|
*
|
||||||
@@ -570,20 +368,6 @@ public class ChineseNumberFormatter {
|
|||||||
return DIGITS[number * 2 - (isUseTraditional ? 0 : 1)];
|
return DIGITS[number * 2 - (isUseTraditional ? 0 : 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取对应级别的单位
|
|
||||||
*
|
|
||||||
* @param index 级别,0表示各位,1表示十位,2表示百位,以此类推
|
|
||||||
* @param isUseTraditional 是否使用繁体
|
|
||||||
* @return 单位
|
|
||||||
*/
|
|
||||||
private static String getUnitName(final int index, final boolean isUseTraditional) {
|
|
||||||
if (0 == index) {
|
|
||||||
return StrUtil.EMPTY;
|
|
||||||
}
|
|
||||||
return String.valueOf(CHINESE_NAME_VALUE[index * 2 - (isUseTraditional ? 0 : 1)].name);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addPreZero(final StringBuilder chineseStr) {
|
private static void addPreZero(final StringBuilder chineseStr) {
|
||||||
if (StrUtil.isEmpty(chineseStr)) {
|
if (StrUtil.isEmpty(chineseStr)) {
|
||||||
return;
|
return;
|
||||||
@@ -592,39 +376,4 @@ public class ChineseNumberFormatter {
|
|||||||
chineseStr.insert(0, '零');
|
chineseStr.insert(0, '零');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 权位
|
|
||||||
*
|
|
||||||
* @author totalo
|
|
||||||
* @since 5.6.0
|
|
||||||
*/
|
|
||||||
private static class ChineseUnit {
|
|
||||||
/**
|
|
||||||
* 中文权名称
|
|
||||||
*/
|
|
||||||
private final char name;
|
|
||||||
/**
|
|
||||||
* 10的倍数值
|
|
||||||
*/
|
|
||||||
private final int value;
|
|
||||||
/**
|
|
||||||
* 是否为节权位,它不是与之相邻的数字的倍数,而是整个小节的倍数。<br>
|
|
||||||
* 例如二十三万,万是节权位,与三无关,而和二十三关联
|
|
||||||
*/
|
|
||||||
private final boolean secUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构造
|
|
||||||
*
|
|
||||||
* @param name 名称
|
|
||||||
* @param value 值,即10的倍数
|
|
||||||
* @param secUnit 是否为节权位
|
|
||||||
*/
|
|
||||||
public ChineseUnit(final char name, final int value, final boolean secUnit) {
|
|
||||||
this.name = name;
|
|
||||||
this.value = value;
|
|
||||||
this.secUnit = secUnit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,294 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024. looly(loolly@aliyun.com)
|
||||||
|
* Hutool is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* https://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.dromara.hutool.core.math;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.array.ArrayUtil;
|
||||||
|
import org.dromara.hutool.core.text.StrUtil;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 中文数字或金额解析类
|
||||||
|
*
|
||||||
|
* @author fanqun, looly
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class ChineseNumberParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 汉字转阿拉伯数字的
|
||||||
|
*/
|
||||||
|
private static final ChineseUnit[] CHINESE_NAME_VALUE = {
|
||||||
|
new ChineseUnit(' ', 1, false),
|
||||||
|
new ChineseUnit('十', 10, false),
|
||||||
|
new ChineseUnit('拾', 10, false),
|
||||||
|
new ChineseUnit('百', 100, false),
|
||||||
|
new ChineseUnit('佰', 100, false),
|
||||||
|
new ChineseUnit('千', 1000, false),
|
||||||
|
new ChineseUnit('仟', 1000, false),
|
||||||
|
new ChineseUnit('万', 1_0000, true),
|
||||||
|
new ChineseUnit('亿', 1_0000_0000, true),
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把中文转换为数字 如 二百二十 -》 220<br>
|
||||||
|
* <ul>
|
||||||
|
* <li>一百一十二 -》 112</li>
|
||||||
|
* <li>一千零一十二 -》 1012</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param chinese 中文字符
|
||||||
|
* @return 数字
|
||||||
|
* @since 5.6.0
|
||||||
|
*/
|
||||||
|
public static Number parseFromChinese(final String chinese) {
|
||||||
|
if(StrUtil.containsAny(chinese, '元', '圆', '角', '分')){
|
||||||
|
return parseFromChineseMoney(chinese);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseFromChineseNumber(chinese);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把中文转换为数字 如 二百二十 220<br>
|
||||||
|
* <ul>
|
||||||
|
* <li>一百一十二 -》 112</li>
|
||||||
|
* <li>一千零一十二 -》 1012</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param chinese 中文字符
|
||||||
|
* @return 数字
|
||||||
|
* @since 5.6.0
|
||||||
|
*/
|
||||||
|
public static int parseFromChineseNumber(final String chinese) {
|
||||||
|
final int length = chinese.length();
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
// 节总和
|
||||||
|
int section = 0;
|
||||||
|
int number = 0;
|
||||||
|
ChineseUnit unit = null;
|
||||||
|
char c;
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
c = chinese.charAt(i);
|
||||||
|
final int num = chineseToNumber(c);
|
||||||
|
if (num >= 0) {
|
||||||
|
if (num == 0) {
|
||||||
|
// 遇到零时节结束,权位失效,比如两万二零一十
|
||||||
|
if (number > 0 && null != unit) {
|
||||||
|
section += number * (unit.value / 10);
|
||||||
|
}
|
||||||
|
unit = null;
|
||||||
|
} else if (number > 0) {
|
||||||
|
// 多个数字同时出现,报错
|
||||||
|
throw new IllegalArgumentException(StrUtil.format("Bad number '{}{}' at: {}", chinese.charAt(i - 1), c, i));
|
||||||
|
}
|
||||||
|
// 普通数字
|
||||||
|
number = num;
|
||||||
|
} else {
|
||||||
|
unit = chineseToUnit(c);
|
||||||
|
if (null == unit) {
|
||||||
|
// 出现非法字符
|
||||||
|
throw new IllegalArgumentException(StrUtil.format("Unknown unit '{}' at: {}", c, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
//单位
|
||||||
|
if (unit.secUnit) {
|
||||||
|
// 节单位,按照节求和
|
||||||
|
section = (section + number) * unit.value;
|
||||||
|
result += section;
|
||||||
|
section = 0;
|
||||||
|
} else {
|
||||||
|
// 非节单位,和单位前的单数字组合为值
|
||||||
|
int unitNumber = number;
|
||||||
|
if (0 == number && 0 == i) {
|
||||||
|
// issue#1726,对于单位开头的数组,默认赋予1
|
||||||
|
// 十二 -> 一十二
|
||||||
|
// 百二 -> 一百二
|
||||||
|
unitNumber = 1;
|
||||||
|
}
|
||||||
|
section += (unitNumber * unit.value);
|
||||||
|
}
|
||||||
|
number = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (number > 0 && null != unit) {
|
||||||
|
number = number * (unit.value / 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result + section + number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 中文大写数字金额转换为数字,返回结果以元为单位的BigDecimal类型数字<br>
|
||||||
|
* 如:
|
||||||
|
* “陆万柒仟伍佰伍拾陆元叁角贰分”返回“67556.32”
|
||||||
|
* “叁角贰分”返回“0.32”
|
||||||
|
*
|
||||||
|
* @param chineseMoneyAmount 中文大写数字金额
|
||||||
|
* @return 返回结果以元为单位的BigDecimal类型数字
|
||||||
|
*/
|
||||||
|
public static BigDecimal parseFromChineseMoney(final String chineseMoneyAmount) {
|
||||||
|
if (StrUtil.isBlank(chineseMoneyAmount)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int yi = chineseMoneyAmount.indexOf("元");
|
||||||
|
if (yi == -1) {
|
||||||
|
yi = chineseMoneyAmount.indexOf("圆");
|
||||||
|
}
|
||||||
|
final int ji = chineseMoneyAmount.indexOf("角");
|
||||||
|
final int fi = chineseMoneyAmount.indexOf("分");
|
||||||
|
|
||||||
|
// 先找到单位为元的数字
|
||||||
|
String yStr = null;
|
||||||
|
if (yi > 0) {
|
||||||
|
yStr = chineseMoneyAmount.substring(0, yi);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 再找到单位为角的数字
|
||||||
|
String jStr = null;
|
||||||
|
if (ji > 0) {
|
||||||
|
if (yi >= 0) {
|
||||||
|
//前面有元,角肯定要在元后面
|
||||||
|
if (ji > yi) {
|
||||||
|
jStr = chineseMoneyAmount.substring(yi + 1, ji);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//没有元,只有角
|
||||||
|
jStr = chineseMoneyAmount.substring(0, ji);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 再找到单位为分的数字
|
||||||
|
String fStr = null;
|
||||||
|
if (fi > 0) {
|
||||||
|
if (ji >= 0) {
|
||||||
|
//有角,分肯定在角后面
|
||||||
|
if (fi > ji) {
|
||||||
|
fStr = chineseMoneyAmount.substring(ji + 1, fi);
|
||||||
|
}
|
||||||
|
} else if (yi > 0) {
|
||||||
|
//没有角,有元,那就坐元后面找
|
||||||
|
if (fi > yi) {
|
||||||
|
fStr = chineseMoneyAmount.substring(yi + 1, fi);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//没有元、角,只有分
|
||||||
|
fStr = chineseMoneyAmount.substring(0, fi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//元、角、分
|
||||||
|
int y = 0, j = 0, f = 0;
|
||||||
|
if (StrUtil.isNotBlank(yStr)) {
|
||||||
|
y = parseFromChineseNumber(yStr);
|
||||||
|
}
|
||||||
|
if (StrUtil.isNotBlank(jStr)) {
|
||||||
|
j = parseFromChineseNumber(jStr);
|
||||||
|
}
|
||||||
|
if (StrUtil.isNotBlank(fStr)) {
|
||||||
|
f = parseFromChineseNumber(fStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal amount = new BigDecimal(y);
|
||||||
|
amount = amount.add(BigDecimal.valueOf(j).divide(BigDecimal.TEN, 2, RoundingMode.HALF_UP));
|
||||||
|
amount = amount.add(BigDecimal.valueOf(f).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找对应的权对象
|
||||||
|
*
|
||||||
|
* @param chinese 中文权位名
|
||||||
|
* @return 权对象
|
||||||
|
*/
|
||||||
|
private static ChineseUnit chineseToUnit(final char chinese) {
|
||||||
|
for (final ChineseUnit chineseNameValue : CHINESE_NAME_VALUE) {
|
||||||
|
if (chineseNameValue.name == chinese) {
|
||||||
|
return chineseNameValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将汉字单个数字转换为int类型数字
|
||||||
|
*
|
||||||
|
* @param chinese 汉字数字,支持简体和繁体
|
||||||
|
* @return 数字,-1表示未找到
|
||||||
|
* @since 5.6.4
|
||||||
|
*/
|
||||||
|
private static int chineseToNumber(char chinese) {
|
||||||
|
if ('两' == chinese) {
|
||||||
|
// 口语纠正
|
||||||
|
chinese = '二';
|
||||||
|
}
|
||||||
|
final int i = ArrayUtil.indexOf(ChineseNumberFormatter.DIGITS, chinese);
|
||||||
|
if (i > 0) {
|
||||||
|
return (i + 1) / 2;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取对应级别的单位
|
||||||
|
*
|
||||||
|
* @param index 级别,0表示各位,1表示十位,2表示百位,以此类推
|
||||||
|
* @param isUseTraditional 是否使用繁体
|
||||||
|
* @return 单位
|
||||||
|
*/
|
||||||
|
static String getUnitName(final int index, final boolean isUseTraditional) {
|
||||||
|
if (0 == index) {
|
||||||
|
return StrUtil.EMPTY;
|
||||||
|
}
|
||||||
|
return String.valueOf(CHINESE_NAME_VALUE[index * 2 - (isUseTraditional ? 0 : 1)].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权位
|
||||||
|
*
|
||||||
|
* @author totalo
|
||||||
|
* @since 5.6.0
|
||||||
|
*/
|
||||||
|
private static class ChineseUnit {
|
||||||
|
/**
|
||||||
|
* 中文权名称
|
||||||
|
*/
|
||||||
|
private final char name;
|
||||||
|
/**
|
||||||
|
* 10的倍数值
|
||||||
|
*/
|
||||||
|
private final int value;
|
||||||
|
/**
|
||||||
|
* 是否为节权位,它不是与之相邻的数字的倍数,而是整个小节的倍数。<br>
|
||||||
|
* 例如二十三万,万是节权位,与三无关,而和二十三关联
|
||||||
|
*/
|
||||||
|
private final boolean secUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param name 名称
|
||||||
|
* @param value 值,即10的倍数
|
||||||
|
* @param secUnit 是否为节权位
|
||||||
|
*/
|
||||||
|
public ChineseUnit(final char name, final int value, final boolean secUnit) {
|
||||||
|
this.name = name;
|
||||||
|
this.value = value;
|
||||||
|
this.secUnit = secUnit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
package org.dromara.hutool.core.math;
|
package org.dromara.hutool.core.math;
|
||||||
|
|
||||||
import org.dromara.hutool.core.math.NumberUtil;
|
|
||||||
import org.dromara.hutool.core.text.StrUtil;
|
import org.dromara.hutool.core.text.StrUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,7 +21,7 @@ import org.dromara.hutool.core.text.StrUtil;
|
|||||||
* @author Looly, totalo
|
* @author Looly, totalo
|
||||||
* @since 3.0.9
|
* @since 3.0.9
|
||||||
*/
|
*/
|
||||||
public class NumberWordFormatter {
|
public class EnglishNumberFormatter {
|
||||||
|
|
||||||
private static final String[] NUMBER = new String[]{"", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN",
|
private static final String[] NUMBER = new String[]{"", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN",
|
||||||
"EIGHT", "NINE"};
|
"EIGHT", "NINE"};
|
@@ -283,21 +283,21 @@ public class NumberChineseFormatterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void chineseToNumberTest(){
|
public void chineseToNumberTest(){
|
||||||
Assertions.assertEquals(0, ChineseNumberFormatter.parseFromChinese("零"));
|
Assertions.assertEquals(0, ChineseNumberParser.parseFromChinese("零"));
|
||||||
Assertions.assertEquals(102, ChineseNumberFormatter.parseFromChinese("一百零二"));
|
Assertions.assertEquals(102, ChineseNumberParser.parseFromChinese("一百零二"));
|
||||||
Assertions.assertEquals(112, ChineseNumberFormatter.parseFromChinese("一百一十二"));
|
Assertions.assertEquals(112, ChineseNumberParser.parseFromChinese("一百一十二"));
|
||||||
Assertions.assertEquals(1012, ChineseNumberFormatter.parseFromChinese("一千零一十二"));
|
Assertions.assertEquals(1012, ChineseNumberParser.parseFromChinese("一千零一十二"));
|
||||||
Assertions.assertEquals(1000000, ChineseNumberFormatter.parseFromChinese("一百万"));
|
Assertions.assertEquals(1000000, ChineseNumberParser.parseFromChinese("一百万"));
|
||||||
Assertions.assertEquals(2000100112, ChineseNumberFormatter.parseFromChinese("二十亿零一十万零一百一十二"));
|
Assertions.assertEquals(2000100112, ChineseNumberParser.parseFromChinese("二十亿零一十万零一百一十二"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void chineseToNumberTest2(){
|
public void chineseToNumberTest2(){
|
||||||
Assertions.assertEquals(120, ChineseNumberFormatter.parseFromChinese("一百二"));
|
Assertions.assertEquals(120, ChineseNumberParser.parseFromChinese("一百二"));
|
||||||
Assertions.assertEquals(1200, ChineseNumberFormatter.parseFromChinese("一千二"));
|
Assertions.assertEquals(1200, ChineseNumberParser.parseFromChinese("一千二"));
|
||||||
Assertions.assertEquals(22000, ChineseNumberFormatter.parseFromChinese("两万二"));
|
Assertions.assertEquals(22000, ChineseNumberParser.parseFromChinese("两万二"));
|
||||||
Assertions.assertEquals(22003, ChineseNumberFormatter.parseFromChinese("两万二零三"));
|
Assertions.assertEquals(22003, ChineseNumberParser.parseFromChinese("两万二零三"));
|
||||||
Assertions.assertEquals(22010, ChineseNumberFormatter.parseFromChinese("两万二零一十"));
|
Assertions.assertEquals(22010, ChineseNumberParser.parseFromChinese("两万二零一十"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -305,16 +305,16 @@ public class NumberChineseFormatterTest {
|
|||||||
// issue#1726,对于单位开头的数组,默认赋予1
|
// issue#1726,对于单位开头的数组,默认赋予1
|
||||||
// 十二 -> 一十二
|
// 十二 -> 一十二
|
||||||
// 百二 -> 一百二
|
// 百二 -> 一百二
|
||||||
Assertions.assertEquals(12, ChineseNumberFormatter.parseFromChinese("十二"));
|
Assertions.assertEquals(12, ChineseNumberParser.parseFromChinese("十二"));
|
||||||
Assertions.assertEquals(120, ChineseNumberFormatter.parseFromChinese("百二"));
|
Assertions.assertEquals(120, ChineseNumberParser.parseFromChinese("百二"));
|
||||||
Assertions.assertEquals(1300, ChineseNumberFormatter.parseFromChinese("千三"));
|
Assertions.assertEquals(1300, ChineseNumberParser.parseFromChinese("千三"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void badNumberTest(){
|
public void badNumberTest(){
|
||||||
Assertions.assertThrows(IllegalArgumentException.class, ()->{
|
Assertions.assertThrows(IllegalArgumentException.class, ()->{
|
||||||
// 连续数字检查
|
// 连续数字检查
|
||||||
ChineseNumberFormatter.parseFromChinese("一百一二三");
|
ChineseNumberParser.parseFromChinese("一百一二三");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,7 +322,7 @@ public class NumberChineseFormatterTest {
|
|||||||
public void badNumberTest2(){
|
public void badNumberTest2(){
|
||||||
Assertions.assertThrows(IllegalArgumentException.class, ()->{
|
Assertions.assertThrows(IllegalArgumentException.class, ()->{
|
||||||
// 非法字符
|
// 非法字符
|
||||||
ChineseNumberFormatter.parseFromChinese("一百你三");
|
ChineseNumberParser.parseFromChinese("一百你三");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,13 +373,13 @@ public class NumberChineseFormatterTest {
|
|||||||
* s=叁角贰分, n=0.32
|
* s=叁角贰分, n=0.32
|
||||||
* s=陆万柒仟伍佰伍拾陆元叁角贰分, n=67556.32
|
* s=陆万柒仟伍佰伍拾陆元叁角贰分, n=67556.32
|
||||||
*/
|
*/
|
||||||
Assertions.assertEquals(67556, ChineseNumberFormatter.parseFromChineseMoney("陆万柒仟伍佰伍拾陆圆").longValue());
|
Assertions.assertEquals(67556, ChineseNumberParser.parseFromChineseMoney("陆万柒仟伍佰伍拾陆圆").longValue());
|
||||||
Assertions.assertEquals(67556, ChineseNumberFormatter.parseFromChineseMoney("陆万柒仟伍佰伍拾陆元").longValue());
|
Assertions.assertEquals(67556, ChineseNumberParser.parseFromChineseMoney("陆万柒仟伍佰伍拾陆元").longValue());
|
||||||
Assertions.assertEquals(0.3D, ChineseNumberFormatter.parseFromChineseMoney("叁角").doubleValue(), 0);
|
Assertions.assertEquals(0.3D, ChineseNumberParser.parseFromChineseMoney("叁角").doubleValue(), 0);
|
||||||
Assertions.assertEquals(0.02, ChineseNumberFormatter.parseFromChineseMoney("贰分").doubleValue(), 0);
|
Assertions.assertEquals(0.02, ChineseNumberParser.parseFromChineseMoney("贰分").doubleValue(), 0);
|
||||||
Assertions.assertEquals(67556.3, ChineseNumberFormatter.parseFromChineseMoney("陆万柒仟伍佰伍拾陆元叁角").doubleValue(), 0);
|
Assertions.assertEquals(67556.3, ChineseNumberParser.parseFromChineseMoney("陆万柒仟伍佰伍拾陆元叁角").doubleValue(), 0);
|
||||||
Assertions.assertEquals(67556.02, ChineseNumberFormatter.parseFromChineseMoney("陆万柒仟伍佰伍拾陆元贰分").doubleValue(), 0);
|
Assertions.assertEquals(67556.02, ChineseNumberParser.parseFromChineseMoney("陆万柒仟伍佰伍拾陆元贰分").doubleValue(), 0);
|
||||||
Assertions.assertEquals(0.32, ChineseNumberFormatter.parseFromChineseMoney("叁角贰分").doubleValue(), 0);
|
Assertions.assertEquals(0.32, ChineseNumberParser.parseFromChineseMoney("叁角贰分").doubleValue(), 0);
|
||||||
Assertions.assertEquals(67556.32, ChineseNumberFormatter.parseFromChineseMoney("陆万柒仟伍佰伍拾陆元叁角贰分").doubleValue(), 0);
|
Assertions.assertEquals(67556.32, ChineseNumberParser.parseFromChineseMoney("陆万柒仟伍佰伍拾陆元叁角贰分").doubleValue(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
package org.dromara.hutool.core.math;
|
package org.dromara.hutool.core.math;
|
||||||
|
|
||||||
import org.dromara.hutool.core.math.NumberWordFormatter;
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
@@ -20,37 +19,37 @@ public class NumberWordFormatTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void formatTest() {
|
public void formatTest() {
|
||||||
final String format = NumberWordFormatter.format(100.23);
|
final String format = EnglishNumberFormatter.format(100.23);
|
||||||
Assertions.assertEquals("ONE HUNDRED AND CENTS TWENTY THREE ONLY", format);
|
Assertions.assertEquals("ONE HUNDRED AND CENTS TWENTY THREE ONLY", format);
|
||||||
|
|
||||||
final String format2 = NumberWordFormatter.format("2100.00");
|
final String format2 = EnglishNumberFormatter.format("2100.00");
|
||||||
Assertions.assertEquals("TWO THOUSAND ONE HUNDRED AND CENTS ONLY", format2);
|
Assertions.assertEquals("TWO THOUSAND ONE HUNDRED AND CENTS ONLY", format2);
|
||||||
|
|
||||||
final String format3 = NumberWordFormatter.format("1234567890123.12");
|
final String format3 = EnglishNumberFormatter.format("1234567890123.12");
|
||||||
Assertions.assertEquals("ONE TRILLION TWO HUNDRED AND THIRTY FOUR BILLION FIVE HUNDRED AND SIXTY SEVEN MILLION EIGHT HUNDRED AND NINETY THOUSAND ONE HUNDRED AND TWENTY THREE AND CENTS TWELVE ONLY", format3);
|
Assertions.assertEquals("ONE TRILLION TWO HUNDRED AND THIRTY FOUR BILLION FIVE HUNDRED AND SIXTY SEVEN MILLION EIGHT HUNDRED AND NINETY THOUSAND ONE HUNDRED AND TWENTY THREE AND CENTS TWELVE ONLY", format3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void formatSimpleTest() {
|
public void formatSimpleTest() {
|
||||||
final String format1 = NumberWordFormatter.formatSimple(1200, false);
|
final String format1 = EnglishNumberFormatter.formatSimple(1200, false);
|
||||||
Assertions.assertEquals("1.2k", format1);
|
Assertions.assertEquals("1.2k", format1);
|
||||||
|
|
||||||
final String format2 = NumberWordFormatter.formatSimple(4384324, false);
|
final String format2 = EnglishNumberFormatter.formatSimple(4384324, false);
|
||||||
Assertions.assertEquals("4.38m", format2);
|
Assertions.assertEquals("4.38m", format2);
|
||||||
|
|
||||||
final String format3 = NumberWordFormatter.formatSimple(4384324, true);
|
final String format3 = EnglishNumberFormatter.formatSimple(4384324, true);
|
||||||
Assertions.assertEquals("438.43w", format3);
|
Assertions.assertEquals("438.43w", format3);
|
||||||
|
|
||||||
final String format4 = NumberWordFormatter.formatSimple(4384324);
|
final String format4 = EnglishNumberFormatter.formatSimple(4384324);
|
||||||
Assertions.assertEquals("438.43w", format4);
|
Assertions.assertEquals("438.43w", format4);
|
||||||
|
|
||||||
final String format5 = NumberWordFormatter.formatSimple(438);
|
final String format5 = EnglishNumberFormatter.formatSimple(438);
|
||||||
Assertions.assertEquals("438", format5);
|
Assertions.assertEquals("438", format5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void formatSimpleTest2(){
|
public void formatSimpleTest2(){
|
||||||
final String s = NumberWordFormatter.formatSimple(1000);
|
final String s = EnglishNumberFormatter.formatSimple(1000);
|
||||||
Assertions.assertEquals("1k", s);
|
Assertions.assertEquals("1k", s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user