金融、票據系統常需將阿拉伯數字金額轉為中文大寫(壹貳叁肆伍陸柒捌玖)。本文提供支持超大數值(至大數)、小數角分、零處理規範的完整實現。
// 數字大寫
private static final String[] NUM = {"零","壹","貳","叁","肆","伍","陸","柒","捌","玖"};
// 十進制單位
private static final String[] DW = {"","拾","佰","仟"};
// 萬進制單位(擴展至大數)
private static final String[] DW2 = {"","萬","億","兆","京","垓","秭","穰","溝","澗","正","載","極",
"恆河沙","阿僧祇","那由他","不可思議","無量","大數"};
// 角分單位
private static final String[] DW1 = {"角","分"};
public static String parse(String str) {
// 1. 校驗合法數字格式
if (!str.matches("^\\d+(\\.\\d+)?$"))
throw new IllegalArgumentException("非法金額格式: " + str);
// 2. 分離整數/小數部分
String integer = "", decimal = "";
int dotPos = str.indexOf('.');
if (dotPos >= 0) {
integer = str.substring(0, dotPos);
decimal = str.substring(dotPos + 1).replaceAll("(.*?)(0+)$", "$1"); // 去尾部零
} else {
integer = str;
}
integer = integer.replaceAll("^(0+)(.*)", "$2"); // 去首部零
if (integer.isEmpty() && !decimal.isEmpty()) integer = "0";
// 3. 分別解析
String intStr = parseInteger(integer);
String decStr = parseDecimal(decimal, !intStr.isEmpty());
// 4. 組裝結果
if (!intStr.isEmpty()) {
intStr += "元";
// 整數末尾為0且小數不以0開頭,補「零」
if (integer.endsWith("0") && !decimal.isEmpty() && !decimal.startsWith("0"))
intStr += "零";
} else if (decStr.isEmpty()) {
intStr = "零元";
}
return intStr + (decStr.isEmpty() ? "整" : decStr);
}
private static String parseInteger(String str) {
if (str == null || str.isEmpty()) return "";
// 反轉字符串,每4位分組
StringBuilder rev = new StringBuilder(str).reverse();
List groups = new ArrayList<>();
for (int i = 0; i < rev.length(); i += 4) {
int end = Math.min(i + 4, rev.length());
groups.add(new StringBuilder(rev.substring(i, end)).reverse().toString());
}
// 處理每組
StringBuilder result = new StringBuilder();
for (int i = groups.size() - 1; i >= 0; i--) {
String group = groups.get(i);
String groupStr = parseGroup(group);
if (!groupStr.isEmpty()) {
result.append(groupStr).append(DW2[i]);
} else if (i > 0 && !result.toString().endsWith(NUM[0])) {
// 組內全零但非最高位,需補零(如 10001 → 壹萬零壹)
result.append(NUM[0]);
}
}
return result.toString();
}
private static String parseGroup(String group) {
StringBuilder sb = new StringBuilder();
boolean lastZero = false;
for (int i = group.length() - 1; i >= 0; i--) {
int digit = group.charAt(i) - '0';
if (digit == 0) {
lastZero = true;
} else {
if (lastZero) sb.append(NUM[0]);
sb.append(NUM[digit]).append(DW[group.length() - 1 - i]);
lastZero = false;
}
}
return sb.toString();
}
private static String parseDecimal(String decimal, boolean hasInteger) {
if (decimal == null || decimal.isEmpty()) return "";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < Math.min(decimal.length(), 2); i++) {
int digit = decimal.charAt(i) - '0';
if (digit != 0) {
sb.append(NUM[digit]).append(DW1[i]);
} else if (hasInteger && i == 0 && decimal.length() > 1 && decimal.charAt(1) != '0') {
// 整數部分存在且角為零分不為零:壹元零伍分
sb.append(NUM[0]);
}
}
return sb.toString();
}
| 輸入 | 輸出 |
|---|---|
| 0 | 零元整 |
| 100 | 壹佰元整 |
| 100.05 | 壹佰元零伍分 |
| 10001 | 壹萬零壹元整 |
| 1234567890.12 | 壹拾貳億叁仟肆佰伍拾陸萬柒仟捌佰玖拾元壹角貳分 |
| 0.01 | 零元壹分 |
BigDecimal 重載避免精度丟失