中文大写数字转换为阿拉伯数字

Java常用方法   2025-01-12 15:18   248   0  
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;
    }

}


博客评论
还没有人评论,赶紧抢个沙发~
发表评论
说明:请文明发言,共建和谐网络,您的个人信息不会被公开显示。