将数字转换为汉字的算法
本帖最后由 紫蝶冰澜 于 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以上都支持,欢迎测试,甚至提出优化建议,一起交流,这个功能可以服务于文字转语音时,对数字读取的准确性,使得语音不是那么生硬
```java
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;
this.isNeg = this.iStr.charAt(0) == '-';
if (this.isNeg) this.iStr = this.iStr.substring(1);
this.fStr = s.length == 2 ? s : "";
if (this.fStr.isEmpty() && "0".equals(this.iStr)) this.isNeg = false;
}
public String parse() {
StringBuilder sb = new StringBuilder();
if (isNeg) sb.append(CN_CONST);
String s = _0(parseInteger());
sb.append(s.isEmpty() ? CN_NUMBER : s);
if (this.fStr != null && !this.fStr.isEmpty()) sb.append(CN_CONST).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)) {
sb.append(CN_NUMBER);
} else {
sb.append(_0(parse_4(ss)))
.append(parseIntegerUnit(g));
}
}
return sb.toString();
}
private String parseIntegerUnit(int g) {
StringBuilder sb = new StringBuilder();
if (g == 0) return CN_UNIT_2;
if (g % 2 == 1) sb.append(CN_UNIT_2);
for (int i = 0; i < g - 1; i = i + 2) sb.append(CN_UNIT_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;
sb.append(s);
if (!CN_NUMBER.equals(s)) {
String u = CN_UNIT_1;
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.charAt(0)
&& s.charAt(1) == CN_UNIT_1.charAt(0)
? s.substring(1) : s;
}
private String _0(String s) {
return s.replace(CN_NUMBER + CN_NUMBER + CN_NUMBER, CN_NUMBER)
.replace(CN_NUMBER + CN_NUMBER, CN_NUMBER)
.replaceAll(CN_NUMBER + "+$", "");
}
private String[] _4(String n) {
int l = n.length();
int g = (l + 3) / 4;
String[] r = new String;
for (int i = 0; i < g; i++) {
int e = l - i * 4;
int s = Math.max(0, e - 4);
r = 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);
}
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=>负一万亿零二十三亿四千万五千六百点一零零零
```
凑巧了这不是,前段时间刚好因为需求实现了数字时间转中文时间的工具方法,也分享一下给大伙们哈哈哈
private static final String[] CHINESE_NUMBERS = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十"};
private static final String[] CHINESE_MONTHS = {"", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"};
/**
* 返回指定格式的时间字符串
* @AuThor Carinx
* @date 2021/12/22 16:29
* @Param value 原时间字符串
* @param pattern 返回时间格式
* @Return java.lang.String 没有匹配到相关时间格式则返回原字符串
*
**/
public static String parseDate(String value, String pattern) {
if (value == null || "".equals(value)) {
return null;
}
DateFormat dateFormat;
//兼容高精度情况
if (value.matches("^{1}{3}-(?:0|1)-(?:0|\\d|3)\\s+(?:\\d|2):\\d:\\d(?:\\.\\d+)?$")){
dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
else if (value.matches("^{1}{3}-(?:0|1)-(?:0|\\d|3)$")) {
dateFormat = new SimpleDateFormat("yyyy-MM-dd");
}
else if (value.matches("^{1}{3}(?:0|1)(?:0|\\d|3)$")) {
dateFormat = new SimpleDateFormat("yyyyMMdd");
}
else if (value.matches("^{1}{3}/(?:0|1)/(?:0|\\d|3)$")) {
dateFormat = new SimpleDateFormat("yyyy/MM/dd");
}
else if (value.matches("^{1}{3}年(?:0|1)月(?:0|\\d|3)日$")) {
dateFormat = new SimpleDateFormat("yyyy年MM月dd日");
}
else if (value.matches("^{1}{3}\\.(?:0|1)\\.(?:0|\\d|3)$")) {
dateFormat = new SimpleDateFormat("yyyy.MM.dd");
}
else if (value.matches("^{1}{3}\\.(?:0|1)$")) {
dateFormat = new SimpleDateFormat("yyyy.MM");
}
else if (value.matches("^(?:\\d|2):\\d:\\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);
}
result.append("年");
}
// 转换月份
if (ChinesePattern == 1 || ChinesePattern == 2) {
result.append(CHINESE_MONTHS).append("月");
}
// 转换日期
if (ChinesePattern == 1) {
if (day <= 10) {
result.append("初").append(CHINESE_NUMBERS);
} else if (day < 20) {
result.append("十").append(CHINESE_NUMBERS);
} else if (day == 20) {
result.append("二十");
} else if (day < 30) {
result.append("二十").append(CHINESE_NUMBERS);
} else if (day == 30) {
result.append("三十");
} else {
result.append("三十").append(CHINESE_NUMBERS);
}
result.append("日");
}
return result.toString();
}
借鉴学习了 密码学,这是密码学 大佬,要是改成汉字大写的那种字可以吗? 学习学习 这种的,用AI工具生成很方便的 支持一下原创 可以再完善一下,能转换为大写金额的 大单位存一个循环列表不是更好吗
页:
[1]
2