吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 730|回复: 16
收起左侧

[Java 原创] 将数字转换为汉字的算法

[复制链接]
紫蝶冰澜 发表于 2024-10-29 22:54
本帖最后由 紫蝶冰澜 于 2024-10-30 12:20 编辑

代码思路

  1. 使用了BigInteger和BigDecimal,这样可以省去对字符串是否为数字的判断,也方便了后续直接使用字符串进行处理
  2. 先找到小数点,将数字分为两个部分,整数部分还可以确定符号性,确定后,将整数部分改为正数,方便后续处理,这也是类的三个字段的由来
  3. 小数部分很好处理,直接转换就行
  4. 整数部分每4位分为一组
  5. 每组的4位数在转换时,依次转换,遇到0时,不需要跟上单位
  6. 我预留了处理一十几的读数,这样就能忽略最高位的一
  7. 每组的4位数内,高位的“零”需要保留一个,因为分割数组时不会出现最高位是0的情况,多亏了BigInteger和BigDecimal的toString方法
  8. 中间的两个0可以连读为一个0,末尾的连续0就不读了
  9. 如果整组4个数都是0,需要按照最高位是0的情况保留一个0
  10. 已经分好组的单位,可以发现规律,先是“万”,然后是“亿”,剩下的就靠循环就能补足“亿”即可

代码

java5以上都支持,欢迎测试,甚至提出优化建议,一起交流,这个功能可以服务于文字转语音时,对数字读取的准确性,使得语音不是那么生硬

import java.math.BigDecimal;
import java.math.BigInteger;

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i <= 31; i++) {
            toStr(i);
        }
        for (int i = 50998; i <= 51010; i++) {
            toStr(i);
        }
        for (int i = 99998; i <= 100002; i++) {
            toStr(i);
        }

        toStr(-1200001234);

        String s = "-0.1234567890123";
        System.out.println(s + "=>" + new CN_NumString(new BigDecimal(s)).parse());

        s = "0.0001";
        System.out.println(s + "=>" + new CN_NumString(new BigDecimal(s)).parse());

        s = "-1002340005600.1000";
        System.out.println(s + "=>" + new CN_NumString(new BigDecimal(s)).parse());
    }

    public static void toStr(int i) {
        System.out.println(i + "=>" + new CN_NumString(new BigDecimal(Integer.toString(i))).parse());
    }
}

class CN_NumString {
    private static String[] CN_NUMBER = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"};
    private static String[] CN_CONST = {"负", "点"};
    private static String[] CN_UNIT_1 = {"", "十", "百", "千"};
    private static String[] CN_UNIT_2 = {"", "万", "亿"};

    private boolean isNeg;
    private String iStr;
    private String fStr;

    public CN_NumString(BigDecimal b) {
        String s = b.toString();
        CN_NumString n = new CN_NumString(s);
        this.isNeg = n.isNeg;
        this.iStr = n.iStr;
        this.fStr = n.fStr;
    }

    public CN_NumString(BigInteger b) {
        String s = b.toString();
        CN_NumString n = new CN_NumString(s);
        this.isNeg = n.isNeg;
        this.iStr = n.iStr;
        this.fStr = "";
    }

    private CN_NumString(String string) {
        String[] s = string.split("\\.");
        this.iStr = s[0];
        this.isNeg = this.iStr.charAt(0) == '-';
        if (this.isNeg) this.iStr = this.iStr.substring(1);
        this.fStr = s.length == 2 ? s[1] : "";
        if (this.fStr.isEmpty() && "0".equals(this.iStr)) this.isNeg = false;
    }

    public String parse() {
        StringBuilder sb = new StringBuilder();
        if (isNeg) sb.append(CN_CONST[0]);
        String s = _0(parseInteger());
        sb.append(s.isEmpty() ? CN_NUMBER[0] : s);
        if (this.fStr != null && !this.fStr.isEmpty()) sb.append(CN_CONST[1]).append(parseFloat());
        return sb.toString();
    }

    private String parseInteger() {
        StringBuilder sb = new StringBuilder();
        String[] ss = _4(this.iStr);
        for (int i = 0; i < ss.length; i++) {
            int g = ss.length - 1 - i;
            if ("0000".equals(ss[g])) {
                sb.append(CN_NUMBER[0]);
            } else {
                sb.append(_0(parse_4(ss[g])))
                        .append(parseIntegerUnit(g));
            }
        }
        return sb.toString();
    }

    private String parseIntegerUnit(int g) {
        StringBuilder sb = new StringBuilder();
        if (g == 0) return CN_UNIT_2[0];
        if (g % 2 == 1) sb.append(CN_UNIT_2[1]);
        for (int i = 0; i < g - 1; i = i + 2) sb.append(CN_UNIT_2[2]);
        return sb.toString();
    }

    private String parse_4(String n) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n.length(); i++) {
            String s = CN_NUMBER[n.charAt(i) - '0'];
            sb.append(s);
            if (!CN_NUMBER[0].equals(s)) {
                String u = CN_UNIT_1[n.length() - 1 - i];
                sb.append(u);
            }
        }
        return _10(sb.toString());
        //return sb.toString();
    }

    private String _10(String s) {
        return (s.length() == 2 || s.length() == 3)
                && s.charAt(0) == CN_NUMBER[1].charAt(0)
                && s.charAt(1) == CN_UNIT_1[1].charAt(0)
                ? s.substring(1) : s;
    }

    private String _0(String s) {
        return s.replace(CN_NUMBER[0] + CN_NUMBER[0] + CN_NUMBER[0], CN_NUMBER[0])
                .replace(CN_NUMBER[0] + CN_NUMBER[0], CN_NUMBER[0])
                .replaceAll(CN_NUMBER[0] + "+$", "");
    }

    private String[] _4(String n) {
        int l = n.length();
        int g = (l + 3) / 4;
        String[] r = new String[g];
        for (int i = 0; i < g; i++) {
            int e = l - i * 4;
            int s = Math.max(0, e - 4);
            r[i] = n.substring(s, e);
        }
        return r;
    }

    private String parseFloat() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < fStr.length(); i++) {
            sb.append(CN_NUMBER[fStr.charAt(i) - '0']);
        }
        return sb.toString();
    }
}

部分测试结果

0=>零
1=>一
2=>二
3=>三
4=>四
5=>五
6=>六
7=>七
8=>八
9=>九
10=>十
11=>十一
12=>十二
13=>十三
14=>十四
15=>十五
16=>十六
17=>十七
18=>十八
19=>十九
20=>二十
21=>二十一
22=>二十二
23=>二十三
24=>二十四
25=>二十五
26=>二十六
27=>二十七
28=>二十八
29=>二十九
30=>三十
31=>三十一
50998=>五万零九百九十八
50999=>五万零九百九十九
51000=>五万一千
51001=>五万一千零一
51002=>五万一千零二
51003=>五万一千零三
51004=>五万一千零四
51005=>五万一千零五
51006=>五万一千零六
51007=>五万一千零七
51008=>五万一千零八
51009=>五万一千零九
51010=>五万一千零一十
99998=>九万九千九百九十八
99999=>九万九千九百九十九
100000=>十万
100001=>十万零一
100002=>十万零二
-1200001234=>负十二亿零一千二百三十四
-0.1234567890123=>负零点一二三四五六七八九零一二三
0.0001=>零点零零零一
-1002340005600.1000=>负一万亿零二十三亿四千万五千六百点一零零零

免费评分

参与人数 4吾爱币 +9 热心值 +3 收起 理由
Awoodensign + 1 用心讨论,共获提升!
侃遍天下无二人 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
weiqiangjs + 1 用心讨论,共获提升!
arctan1 + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Carinx 发表于 2024-10-30 09:31
凑巧了这不是,前段时间刚好因为需求实现了数字时间转中文时间的工具方法,也分享一下给大伙们哈哈哈
[Java] 纯文本查看 复制代码

    private static final String[] CHINESE_NUMBERS = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十"};
    private static final String[] CHINESE_MONTHS = {"", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"};

     /**
     * 返回指定格式的时间字符串
     * [url=home.php?mod=space&uid=686208]@AuThor[/url] Carinx
     * [url=home.php?mod=space&uid=686237]@date[/url] 2021/12/22 16:29
     * [url=home.php?mod=space&uid=952169]@Param[/url] value 原时间字符串
     * @param pattern 返回时间格式
     * [url=home.php?mod=space&uid=155549]@Return[/url] java.lang.String 没有匹配到相关时间格式则返回原字符串
     *
     **/
    public static String parseDate(String value, String pattern) {

        if (value == null || "".equals(value)) {
            return null;
        }

        DateFormat dateFormat;

        //兼容高精度情况
        if (value.matches("^[12]{1}[0-9]{3}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\\d|3[01])\\s+(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?$")){
            dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
        else if (value.matches("^[12]{1}[0-9]{3}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\\d|3[01])$")) {
            dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        }
        else if (value.matches("^[12]{1}[0-9]{3}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\\d|3[01])$")) {
            dateFormat = new SimpleDateFormat("yyyyMMdd");
        }
        else if (value.matches("^[12]{1}[0-9]{3}/(?:0[1-9]|1[0-2])/(?:0[1-9]|[12]\\d|3[01])$")) {
            dateFormat = new SimpleDateFormat("yyyy/MM/dd");
        }
        else if (value.matches("^[12]{1}[0-9]{3}年(?:0[1-9]|1[0-2])月(?:0[1-9]|[12]\\d|3[01])日$")) {
            dateFormat = new SimpleDateFormat("yyyy年MM月dd日");
        }
        else if (value.matches("^[12]{1}[0-9]{3}\\.(?:0[1-9]|1[0-2])\\.(?:0[1-9]|[12]\\d|3[01])$")) {
            dateFormat = new SimpleDateFormat("yyyy.MM.dd");
        }
        else if (value.matches("^[12]{1}[0-9]{3}\\.(?:0[1-9]|1[0-2])$")) {
            dateFormat = new SimpleDateFormat("yyyy.MM");
        }
        else if (value.matches("^(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d{3})?$")) {
            dateFormat = new SimpleDateFormat("HH:mm:ss");
        }
        //10位数字和13位数字,其中,10位数字表示秒级时间戳,13位数字表示毫秒级时间戳
        else if (value.matches("^\\d{10}|\\d{13}$")) {
            return new SimpleDateFormat(pattern)
                    .format(
                            new Date(Long.parseLong(value))
                    );
        }
        else {
            //没有匹配到相关时间格式则返回原字符串
            return value;
        }

        try {
            return new SimpleDateFormat(pattern).format(dateFormat.parse(value));
        } catch (ParseException e) {
            e.printStackTrace();
            throw new Exception("格式化日期失败!");
        }
    }


    /**
     * 转换日期为中文日期
     * @author Carinx
     * @date 2024/10/21 15:01
     * @param localDate  待转换日期
     * @param ChinesePattern  转换输出的中文日期格式映射值:1年月日, 2年月, 3年
     * @return java.lang.String 中文格式日期
     *
     **/
    public static String convertToChineseDate(LocalDate localDate, int ChinesePattern) {

        int year = localDate.getYear();
        int month = localDate.getMonthValue();
        int day = localDate.getDayOfMonth();

        StringBuilder result = new StringBuilder();

        // 转换年份
        if (ChinesePattern == 1 || ChinesePattern == 2 || ChinesePattern == 3) {

            for (char c : String.valueOf(year).toCharArray()) {
                result.append(CHINESE_NUMBERS[Character.getNumericValue(c)]);
            }
            result.append("年");

        }

        // 转换月份
        if (ChinesePattern == 1 || ChinesePattern == 2) {
            result.append(CHINESE_MONTHS[month]).append("月");
        }

        // 转换日期
        if (ChinesePattern == 1) {
            if (day <= 10) {
                result.append("初").append(CHINESE_NUMBERS[day]);
            } else if (day < 20) {
                result.append("十").append(CHINESE_NUMBERS[day % 10]);
            } else if (day == 20) {
                result.append("二十");
            } else if (day < 30) {
                result.append("二十").append(CHINESE_NUMBERS[day % 10]);
            } else if (day == 30) {
                result.append("三十");
            } else {
                result.append("三十").append(CHINESE_NUMBERS[day % 10]);
            }
            result.append("日");
        }

        return result.toString();
    }

fhlfxtd 发表于 2024-10-30 07:21
arctan1 发表于 2024-10-30 07:22
q27557923 发表于 2024-10-30 15:54
大佬,要是改成汉字大写的那种字可以吗?
tengfei123456 发表于 2024-10-30 16:01
学习学习
dongshan1986 发表于 2024-10-30 16:48
这种的,用AI工具生成很方便的
telnetpig 发表于 2024-10-30 17:20
支持一下原创
upfour 发表于 2024-10-30 21:16
可以再完善一下,能转换为大写金额的
wasd71 发表于 2024-10-31 20:00
大单位存一个循环列表不是更好吗
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 09:25

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表