mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
fix code
This commit is contained in:
@@ -1047,7 +1047,7 @@ public class Convert {
|
|||||||
* @return 数字
|
* @return 数字
|
||||||
* @since 5.6.0
|
* @since 5.6.0
|
||||||
*/
|
*/
|
||||||
public static int chineseToNumber(final String number){
|
public static BigDecimal chineseToNumber(final String number){
|
||||||
return ChineseNumberParser.parseFromChineseNumber(number);
|
return ChineseNumberParser.parseFromChineseNumber(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
package org.dromara.hutool.core.math;
|
package org.dromara.hutool.core.math;
|
||||||
|
|
||||||
import org.dromara.hutool.core.array.ArrayUtil;
|
import org.dromara.hutool.core.array.ArrayUtil;
|
||||||
|
import org.dromara.hutool.core.lang.Assert;
|
||||||
import org.dromara.hutool.core.text.StrUtil;
|
import org.dromara.hutool.core.text.StrUtil;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@@ -52,8 +53,8 @@ public class ChineseNumberParser {
|
|||||||
* @return 数字
|
* @return 数字
|
||||||
* @since 5.6.0
|
* @since 5.6.0
|
||||||
*/
|
*/
|
||||||
public static Number parseFromChinese(final String chinese) {
|
public static BigDecimal parseFromChinese(final String chinese) {
|
||||||
if(StrUtil.containsAny(chinese, '元', '圆', '角', '分')){
|
if (StrUtil.containsAny(chinese, '元', '圆', '角', '分')) {
|
||||||
return parseFromChineseMoney(chinese);
|
return parseFromChineseMoney(chinese);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,74 +62,36 @@ public class ChineseNumberParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 把中文转换为数字 如 二百二十 220<br>
|
* 把中文转换为数字<br>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>一百一十二 -》 112</li>
|
* <li>一百一十二 -》 112</li>
|
||||||
* <li>一千零一十二 -》 1012</li>
|
* <li>一千零一十二 -》 1012</li>
|
||||||
|
* <li>十二点二三 -》 12.23</li>
|
||||||
|
* <li>三点一四一五九二六五四 -》 3.141592654</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param chinese 中文字符
|
* @param chinese 中文字符
|
||||||
* @return 数字
|
* @return 数字
|
||||||
* @since 5.6.0
|
* @since 5.6.0
|
||||||
*/
|
*/
|
||||||
public static int parseFromChineseNumber(final String chinese) {
|
public static BigDecimal parseFromChineseNumber(final String chinese) {
|
||||||
final int length = chinese.length();
|
Assert.notBlank(chinese, "Chinese number is blank!");
|
||||||
int result = 0;
|
final int dotIndex = chinese.indexOf('点');
|
||||||
|
|
||||||
// 节总和
|
// 整数部分
|
||||||
int section = 0;
|
BigDecimal result = NumberUtil.toBigDecimal(parseLongFromChineseNumber(chinese, dotIndex > 0 ? dotIndex : chinese.length()));
|
||||||
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) {
|
if (dotIndex > 0) {
|
||||||
// 节单位,按照节求和
|
final int length = chinese.length();
|
||||||
section = (section + number) * unit.value;
|
for (int i = dotIndex + 1; i < length; i++) {
|
||||||
result += section;
|
// 保留位数取决于实际数字的位数
|
||||||
section = 0;
|
// result + (numberChar / 10^(i-dotIndex))
|
||||||
} else {
|
result = result.add(NumberUtil.div(chineseToNumber(chinese.charAt(i)), BigDecimal.TEN.pow(i-dotIndex), (length - dotIndex + 1)));
|
||||||
// 非节单位,和单位前的单数字组合为值
|
|
||||||
int unitNumber = number;
|
|
||||||
if (0 == number && 0 == i) {
|
|
||||||
// issue#1726,对于单位开头的数组,默认赋予1
|
|
||||||
// 十二 -> 一十二
|
|
||||||
// 百二 -> 一百二
|
|
||||||
unitNumber = 1;
|
|
||||||
}
|
|
||||||
section += (unitNumber * unit.value);
|
|
||||||
}
|
|
||||||
number = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (number > 0 && null != unit) {
|
return result.stripTrailingZeros();
|
||||||
number = number * (unit.value / 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result + section + number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -192,15 +155,15 @@ public class ChineseNumberParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//元、角、分
|
//元、角、分
|
||||||
int y = 0, j = 0, f = 0;
|
long y = 0, j = 0, f = 0;
|
||||||
if (StrUtil.isNotBlank(yStr)) {
|
if (StrUtil.isNotBlank(yStr)) {
|
||||||
y = parseFromChineseNumber(yStr);
|
y = parseLongFromChineseNumber(yStr, yStr.length());
|
||||||
}
|
}
|
||||||
if (StrUtil.isNotBlank(jStr)) {
|
if (StrUtil.isNotBlank(jStr)) {
|
||||||
j = parseFromChineseNumber(jStr);
|
j = parseLongFromChineseNumber(jStr, jStr.length());
|
||||||
}
|
}
|
||||||
if (StrUtil.isNotBlank(fStr)) {
|
if (StrUtil.isNotBlank(fStr)) {
|
||||||
f = parseFromChineseNumber(fStr);
|
f = parseLongFromChineseNumber(fStr, fStr.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal amount = new BigDecimal(y);
|
BigDecimal amount = new BigDecimal(y);
|
||||||
@@ -209,6 +172,76 @@ public class ChineseNumberParser {
|
|||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把中文整数转换为数字 如 二百二十 220<br>
|
||||||
|
* <ul>
|
||||||
|
* <li>一百一十二 -》 112</li>
|
||||||
|
* <li>一千零一十二 -》 1012</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param chinese 中文字符
|
||||||
|
* @param toIndex 结束位置(不包括),如果提供的是整数,这个为length(),小数则是“点”的位置
|
||||||
|
* @return 数字
|
||||||
|
*/
|
||||||
|
public static long parseLongFromChineseNumber(final String chinese, final int toIndex) {
|
||||||
|
long result = 0;
|
||||||
|
|
||||||
|
// 节总和
|
||||||
|
long section = 0;
|
||||||
|
long number = 0;
|
||||||
|
ChineseUnit unit = null;
|
||||||
|
char c;
|
||||||
|
for (int i = 0; i < toIndex; 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 {
|
||||||
|
// 非节单位,和单位前的单数字组合为值
|
||||||
|
long 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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查找对应的权对象
|
* 查找对应的权对象
|
||||||
*
|
*
|
||||||
|
@@ -281,51 +281,6 @@ public class ChineseNumberFormatterTest {
|
|||||||
Assertions.assertEquals('A', s);
|
Assertions.assertEquals('A', s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void chineseToNumberTest(){
|
|
||||||
Assertions.assertEquals(0, ChineseNumberParser.parseFromChinese("零"));
|
|
||||||
Assertions.assertEquals(102, ChineseNumberParser.parseFromChinese("一百零二"));
|
|
||||||
Assertions.assertEquals(112, ChineseNumberParser.parseFromChinese("一百一十二"));
|
|
||||||
Assertions.assertEquals(1012, ChineseNumberParser.parseFromChinese("一千零一十二"));
|
|
||||||
Assertions.assertEquals(1000000, ChineseNumberParser.parseFromChinese("一百万"));
|
|
||||||
Assertions.assertEquals(2000100112, ChineseNumberParser.parseFromChinese("二十亿零一十万零一百一十二"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void chineseToNumberTest2(){
|
|
||||||
Assertions.assertEquals(120, ChineseNumberParser.parseFromChinese("一百二"));
|
|
||||||
Assertions.assertEquals(1200, ChineseNumberParser.parseFromChinese("一千二"));
|
|
||||||
Assertions.assertEquals(22000, ChineseNumberParser.parseFromChinese("两万二"));
|
|
||||||
Assertions.assertEquals(22003, ChineseNumberParser.parseFromChinese("两万二零三"));
|
|
||||||
Assertions.assertEquals(22010, ChineseNumberParser.parseFromChinese("两万二零一十"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void chineseToNumberTest3(){
|
|
||||||
// issue#1726,对于单位开头的数组,默认赋予1
|
|
||||||
// 十二 -> 一十二
|
|
||||||
// 百二 -> 一百二
|
|
||||||
Assertions.assertEquals(12, ChineseNumberParser.parseFromChinese("十二"));
|
|
||||||
Assertions.assertEquals(120, ChineseNumberParser.parseFromChinese("百二"));
|
|
||||||
Assertions.assertEquals(1300, ChineseNumberParser.parseFromChinese("千三"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void badNumberTest(){
|
|
||||||
Assertions.assertThrows(IllegalArgumentException.class, ()->{
|
|
||||||
// 连续数字检查
|
|
||||||
ChineseNumberParser.parseFromChinese("一百一二三");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void badNumberTest2(){
|
|
||||||
Assertions.assertThrows(IllegalArgumentException.class, ()->{
|
|
||||||
// 非法字符
|
|
||||||
ChineseNumberParser.parseFromChinese("一百你三");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void singleMoneyTest(){
|
public void singleMoneyTest(){
|
||||||
String format = ChineseNumberFormatter.of().setMoneyMode(true).format(0.01);
|
String format = ChineseNumberFormatter.of().setMoneyMode(true).format(0.01);
|
||||||
@@ -359,27 +314,4 @@ public class ChineseNumberFormatterTest {
|
|||||||
format = ChineseNumberFormatter.of().format(1.02);
|
format = ChineseNumberFormatter.of().format(1.02);
|
||||||
Assertions.assertEquals("一点零二", format);
|
Assertions.assertEquals("一点零二", format);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Test
|
|
||||||
public void testChineseMoneyToNumber(){
|
|
||||||
/*
|
|
||||||
* s=陆万柒仟伍佰伍拾陆圆, n=67556
|
|
||||||
* s=陆万柒仟伍佰伍拾陆元, n=67556
|
|
||||||
* s=叁角, n=0.3
|
|
||||||
* s=贰分, n=0.02
|
|
||||||
* s=陆万柒仟伍佰伍拾陆元叁角, n=67556.3
|
|
||||||
* s=陆万柒仟伍佰伍拾陆元贰分, n=67556.02
|
|
||||||
* s=叁角贰分, n=0.32
|
|
||||||
* s=陆万柒仟伍佰伍拾陆元叁角贰分, n=67556.32
|
|
||||||
*/
|
|
||||||
Assertions.assertEquals(67556, ChineseNumberParser.parseFromChineseMoney("陆万柒仟伍佰伍拾陆圆").longValue());
|
|
||||||
Assertions.assertEquals(67556, ChineseNumberParser.parseFromChineseMoney("陆万柒仟伍佰伍拾陆元").longValue());
|
|
||||||
Assertions.assertEquals(0.3D, ChineseNumberParser.parseFromChineseMoney("叁角").doubleValue(), 0);
|
|
||||||
Assertions.assertEquals(0.02, ChineseNumberParser.parseFromChineseMoney("贰分").doubleValue(), 0);
|
|
||||||
Assertions.assertEquals(67556.3, ChineseNumberParser.parseFromChineseMoney("陆万柒仟伍佰伍拾陆元叁角").doubleValue(), 0);
|
|
||||||
Assertions.assertEquals(67556.02, ChineseNumberParser.parseFromChineseMoney("陆万柒仟伍佰伍拾陆元贰分").doubleValue(), 0);
|
|
||||||
Assertions.assertEquals(0.32, ChineseNumberParser.parseFromChineseMoney("叁角贰分").doubleValue(), 0);
|
|
||||||
Assertions.assertEquals(67556.32, ChineseNumberParser.parseFromChineseMoney("陆万柒仟伍佰伍拾陆元叁角贰分").doubleValue(), 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,88 @@
|
|||||||
|
package org.dromara.hutool.core.math;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public class ChineseNumberParserTest {
|
||||||
|
@Test
|
||||||
|
public void chineseToNumberTest(){
|
||||||
|
Assertions.assertEquals(0, parseFromChinese("零"));
|
||||||
|
Assertions.assertEquals(102, parseFromChinese("一百零二"));
|
||||||
|
Assertions.assertEquals(112, parseFromChinese("一百一十二"));
|
||||||
|
Assertions.assertEquals(1012, parseFromChinese("一千零一十二"));
|
||||||
|
Assertions.assertEquals(1000000, parseFromChinese("一百万"));
|
||||||
|
Assertions.assertEquals(2000100112, parseFromChinese("二十亿零一十万零一百一十二"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void chineseToNumberTest2(){
|
||||||
|
Assertions.assertEquals(120, parseFromChinese("一百二"));
|
||||||
|
Assertions.assertEquals(1200, parseFromChinese("一千二"));
|
||||||
|
Assertions.assertEquals(22000, parseFromChinese("两万二"));
|
||||||
|
Assertions.assertEquals(22003, parseFromChinese("两万二零三"));
|
||||||
|
Assertions.assertEquals(22010, parseFromChinese("两万二零一十"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void chineseToNumberTest3(){
|
||||||
|
// issue#1726,对于单位开头的数组,默认赋予1
|
||||||
|
// 十二 -> 一十二
|
||||||
|
// 百二 -> 一百二
|
||||||
|
Assertions.assertEquals(12, parseFromChinese("十二"));
|
||||||
|
Assertions.assertEquals(120, parseFromChinese("百二"));
|
||||||
|
Assertions.assertEquals(1300, parseFromChinese("千三"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void badNumberTest(){
|
||||||
|
Assertions.assertThrows(IllegalArgumentException.class, ()->{
|
||||||
|
// 连续数字检查
|
||||||
|
ChineseNumberParser.parseFromChinese("一百一二三");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void badNumberTest2(){
|
||||||
|
Assertions.assertThrows(IllegalArgumentException.class, ()->{
|
||||||
|
// 非法字符
|
||||||
|
ChineseNumberParser.parseFromChinese("一百你三");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChineseMoneyToNumber(){
|
||||||
|
/*
|
||||||
|
* s=陆万柒仟伍佰伍拾陆圆, n=67556
|
||||||
|
* s=陆万柒仟伍佰伍拾陆元, n=67556
|
||||||
|
* s=叁角, n=0.3
|
||||||
|
* s=贰分, n=0.02
|
||||||
|
* s=陆万柒仟伍佰伍拾陆元叁角, n=67556.3
|
||||||
|
* s=陆万柒仟伍佰伍拾陆元贰分, n=67556.02
|
||||||
|
* s=叁角贰分, n=0.32
|
||||||
|
* s=陆万柒仟伍佰伍拾陆元叁角贰分, n=67556.32
|
||||||
|
*/
|
||||||
|
Assertions.assertEquals(67556, parseFromChinese("陆万柒仟伍佰伍拾陆圆"));
|
||||||
|
Assertions.assertEquals(67556, parseFromChinese("陆万柒仟伍佰伍拾陆元"));
|
||||||
|
Assertions.assertEquals(0.3D, parseFromChinese("叁角"), 0);
|
||||||
|
Assertions.assertEquals(0.02, parseFromChinese("贰分"), 0);
|
||||||
|
Assertions.assertEquals(67556.3, parseFromChinese("陆万柒仟伍佰伍拾陆元叁角"), 0);
|
||||||
|
Assertions.assertEquals(67556.02, parseFromChinese("陆万柒仟伍佰伍拾陆元贰分"), 0);
|
||||||
|
Assertions.assertEquals(0.32, parseFromChinese("叁角贰分"), 0);
|
||||||
|
Assertions.assertEquals(67556.32, parseFromChinese("陆万柒仟伍佰伍拾陆元叁角贰分"), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parseFromChineseNumberTest() {
|
||||||
|
BigDecimal i = ChineseNumberParser.parseFromChineseNumber("十二点二三");
|
||||||
|
Assertions.assertEquals(NumberUtil.toBigDecimal(12.23D), i);
|
||||||
|
|
||||||
|
i = ChineseNumberParser.parseFromChineseNumber("三点一四一五九二六五四");
|
||||||
|
Assertions.assertEquals(NumberUtil.toBigDecimal(3.141592654D), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double parseFromChinese(final String str){
|
||||||
|
return ChineseNumberParser.parseFromChinese(str).doubleValue();
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user