財務系統中將阿拉伯數字金額轉為中文大寫(如 1234.56 → 壹仟貳佰叁拾肆元伍角陸分)是剛需。本文提供健壯、可擴展的完整實現,覆蓋整數/小數、零處理、萬/億單位、負數校驗等邊界情況。
private static final String[] DIGITS = {"零","壹","貳","叁","肆","伍","陸","柒","捌","玖"};
private static final String[] UNITS = {"","拾","佰","仟"}; // 節內單位
private static final String[] SECTIONS = {"","萬","億","兆"}; // 節單位
private static final String[] FRACTION_UNITS = {"角","分","厘"}; // 小數單位
public class ChineseAmountConverter {
public static String convert(String amount) {
if (amount == null || amount.trim().isEmpty()) {
throw new IllegalArgumentException("金額不能為空");
}
String num = amount.trim();
boolean negative = false;
if (num.startsWith("-")) {
negative = true;
num = num.substring(1);
}
// 校驗格式:整數部分最長 16 位(千億級),小數最多 3 位
if (!num.matches("\\d+(\\.\\d{1,3})?")) {
throw new IllegalArgumentException("非法金額格式");
}
String[] parts = num.split("\\.");
String integerPart = parts[0].replaceFirst("^0+", ""); // 去前導零
if (integerPart.isEmpty()) integerPart = "0";
String fractionPart = parts.length > 1 ? parts[1] : "";
StringBuilder sb = new StringBuilder();
if (negative) sb.append("負");
// 整數部分:從低位向高位,四位一節處理
if ("0".equals(integerPart)) {
sb.append("零元");
} else {
sb.append(processInteger(integerPart));
sb.append("元");
}
// 小數部分
if (fractionPart.isEmpty() || fractionPart.matches("0+")) {
sb.append("整");
} else {
sb.append(processFraction(fractionPart));
}
return sb.toString();
}
private static String processInteger(String num) {
StringBuilder res = new StringBuilder();
int len = num.length();
for (int i = 0; i < len; i += 4) {
int end = len - i;
int start = Math.max(0, end - 4);
String section = num.substring(start, end);
String sectionStr = processSection(section);
if (!sectionStr.isEmpty()) {
res.insert(0, sectionStr + SECTIONS[i / 4]);
}
}
return res.toString();
}
private static String processSection(String fourDigits) {
StringBuilder sb = new StringBuilder();
boolean lastZero = false;
for (int i = 0; i < fourDigits.length(); i++) {
int digit = fourDigits.charAt(i) - '0';
int unitPos = fourDigits.length() - 1 - i; // 3=仟 2=佰 1=拾 0=元
if (digit == 0) {
lastZero = true;
} else {
if (lastZero) sb.append(DIGITS[0]);
sb.append(DIGITS[digit]).append(UNITS[unitPos]);
lastZero = false;
}
}
return sb.toString();
}
private static String processFraction(String frac) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < frac.length() && i < FRACTION_UNITS.length; i++) {
int digit = frac.charAt(i) - '0';
if (digit != 0) {
sb.append(DIGITS[digit]).append(FRACTION_UNITS[i]);
} else if (i + 1 < frac.length()) { // 中間零保留,末尾零省略
// 檢查後續是否有非零
boolean hasNonZero = false;
for (int j = i + 1; j < frac.length(); j++) {
if (frac.charAt(j) != '0') { hasNonZero = true; break; }
}
if (hasNonZero) sb.append(DIGITS[0]);
}
}
return sb.toString();
}
}
| 輸入 | 輸出 |
|---|---|
0 | 零元整 |
100909 | 壹拾萬零玖佰零玖元整 |
1234567.89 | 壹佰貳拾叁萬肆仟伍佰陸拾柒元捌角玖分 |
1000.01 | 壹仟元零壹分 |
-0.05 | 負零元伍分 |
BigDecimal 避免浮點精度問題,支持超大金額。@ChineseAmount 實現聲明式校驗轉換。