package com.chenwc.tools;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
/**
* 中文大写数字转换为阿拉伯数字
*
* @author chenwc
* @date 2023/3/2 22:55
*/
public class ChineseToArabicNumerals {
/**
* 汉字数字到阿拉伯数字的映射关系
*/
private static final HashMap<Character, Long> numMap = new HashMap<Character, Long>() {{
put('零', 0L);
put('一', 1L);
put('二', 2L);
put('三', 3L);
put('四', 4L);
put('五', 5L);
put('六', 6L);
put('七', 7L);
put('八', 8L);
put('九', 9L);
put('十', 10L);
put('廿', 20L);
put('卅', 30L);
put('百', 100L);
put('千', 1000L);
put('万', 10_000L);
put('亿', 100_000_000L);
put('壹', 1L);
put('贰', 2L);
put('叁', 3L);
put('肆', 4L);
put('伍', 5L);
put('陆', 6L);
put('柒', 7L);
put('捌', 8L);
put('玖', 9L);
put('拾', 10L);
put('佰', 100L);
put('仟', 1000L);
}};
/**
* 获取映射关系的键
*/
private final static List<Character> keyList = new ArrayList<Character>(){{
addAll(numMap.keySet());
}};
/**
* 中文大写数字转换为阿拉伯数字,示例:壹佰零壹--->101;廿二--->22;二十万五百亿三千零八万一千零卅五--->20050030081035
*
* @param num 中文大写数字
* @return 阿拉伯数字
*/
public static long transChineseNum(String num) {
if (num == null || num.length() == 0)
return 0L;
//特殊情况 :例如 二零一二 一九八七 这种类似年份的数字
long result;
if ((result = transChineseNumYears(num)) != -1) {
return result;
}
result = 0;
//使用栈
Stack<Long> s = new Stack<>();
for (int i = 0; i < num.length(); i++) {
if (numMap.containsKey(num.charAt(i))) {
long curNum = numMap.get(num.charAt(i));
//若栈为空或者当前字符所代表的的数字小于栈顶数字,直接入栈
if (s.isEmpty() || curNum < s.peek()) {
s.push(curNum);
} else {
int temp = 0;
// 当前字符所代表的的数字小于栈顶数字,依次弹出栈顶元素,
// 直至栈顶数字大于当前数字,将弹出的数字相加后乘与当前数字,再将结果入栈
while (!s.isEmpty() && s.peek() < curNum) {
temp += s.pop();
}
temp = (temp == 0 ? 1 : temp);
s.push(temp * curNum);
}
} else {
throw new RuntimeException("字符【" + num.charAt(i) + "】不在值转换范围" + keyList + "内!");
}
}
//转换结束,把栈内所有数值相加得出最后结果
while (!s.isEmpty()) {
result += s.pop();
}
return result;
}
/**
* 中文大写数字转换为阿拉伯数字,特殊情况转换:例如 二零一二,一九八七 这种类似年份的数字
*
* @param num 中文大写数字
* @return 阿拉伯数字
*/
private static long transChineseNumYears(String num) {
for (char c : num.toCharArray()) {
if (numMap.containsKey(c)) {
if (numMap.get(c) >= 10L) {
return -1;
}
} else {
throw new RuntimeException("字符【" + c + "】不在值转换范围" + keyList + "内!");
}
}
long result = 0;
long unit = 1;
//把字符串逐个字符进行进位相乘相加
for (int i = num.length() - 1; i >= 0; i--) {
result += numMap.get(num.charAt(i)) * unit;
unit *= 10;
}
return result;
}
}