財務系統中將數字金額轉為人民幣大寫(壹貳叁...)是剛需。本文提供一個健壯的實現,覆蓋負數、零值、大數值、小數位精度、連續零壓縮等全場景。
long 存整數,Math.round((x - 整數)*100) 取分/角import java.util.ArrayList;
import java.util.List;
public class RMBConverter {
private static final String[] NUM = {"零","壹","貳","叁","肆","伍","陸","柒","捌","玖"};
private static final String[] UNIT_INT = {"元","拾","佰","仟","萬","拾","佰","仟","億","拾","佰","仟","萬","拾","佰","仟"};
private static final String[] UNIT_DEC = {"分","角"}; // 逆序:分、角
public String convert(double amount) {
if (amount == 0) return "零元整";
StringBuilder sb = new StringBuilder();
if (amount < 0) {
sb.append("負");
amount = -amount;
}
long integerPart = (long) amount;
int decimalPart = (int) Math.round((amount - integerPart) * 100); // 四捨五入取分
// 整數部分逆序字符數組
char[] intDigits = String.valueOf(integerPart).toCharArray();
List intParts = new ArrayList<>();
for (int i = 0; i < intDigits.length; i++) {
int digit = intDigits[intDigits.length - 1 - i] - '0'; // 從個位開始
if (digit == 0) {
// 萬/億位必須顯示單位,其他位僅標記零
if (i == 4 || i == 8 || i == 0) {
intParts.add(NUM[0] + UNIT_INT[i]);
} else {
intParts.add(NUM[0]);
}
} else {
intParts.add(NUM[digit] + UNIT_INT[i]);
}
}
// 逆序拼裝整數部分
for (int i = intParts.size() - 1; i >= 0; i--) {
sb.append(intParts.get(i));
}
// 小數部分
char[] decDigits = String.valueOf(decimalPart).toCharArray();
for (int i = 0; i < decDigits.length; i++) {
int digit = decDigits[decDigits.length - 1 - i] - '0'; // 從分位開始
if (digit > 0) {
sb.append(NUM[digit]).append(UNIT_DEC[i]);
}
}
// 後處理:零值壓縮與修正
String result = sb.toString()
.replaceAll("零+", "零") // 連續零合併
.replaceAll("零元", "元")
.replaceAll("零萬", "萬")
.replaceAll("零億", "億")
.replaceAll("億萬", "億"); // 億萬 → 億
// 結尾處理
if (result.endsWith("元")) result += "整";
if (result.endsWith("角")) result += "整"; // 無分時
return result;
}
// 測試
public static void main(String[] args) {
RMBConverter c = new RMBConverter();
System.out.println(c.convert(2001004.10)); // 貳佰萬零壹仟零肆元壹角
System.out.println(c.convert(2000000.10)); // 貳佰萬元壹角
System.out.println(c.convert(0)); // 零元整
System.out.println(c.convert(1121000010000000L)); // 壹仟壹佰貳拾壹兆... (超出長度演示)
System.out.println(c.convert(-123.45)); // 負壹佰貳拾叁元肆角伍分
}
}
| 輸入 | 輸出 | 驗證點 |
|---|---|---|
2001004.10 | 貳佰萬零壹仟零肆元壹角 | 萬位零、仟位零、小數角 |
2000000.10 | 貳佰萬元壹角 | 連續零壓縮、萬位單位保留 |
0 | 零元整 | 零值特判 |
-123.45 | 負壹佰貳拾叁元肆角伍分 | 負數處理 |
1000.00 | 壹仟元整 | 無小數補「整」 |
0.01 | 壹分 | 純小數、無整數部分 |
BigDecimal 替代 double 做金額運算,避免 0.1+0.2=0.30000000000000004 問題。Math.round 四捨五入:0.005 會變 0.01,符合財務習慣;若需截斷請用 BigDecimal.setScale(2, RoundingMode.DOWN)。UNIT_INT 陣列長度決定最大支持到「兆」級,實際需求可動態生成單位陣列。static 單例或無狀態服務注入。人民幣大寫轉換看似字符串拼接,實則蘊含嚴格的財務規範。掌握「逆序遍歷 + 零值壓縮正則 + 單位修正」三板斧,即可應對各種邊界場景。