財務系統、票據打印常需將阿拉伯數字金額轉為人民幣大寫(如:12345.67 → 壹萬貳仟叁佰肆拾伍元陸角柒分)。關鍵難點:分段處理(萬/億)、零值處理、小數角分轉換。
long totalFen = Math.round(amount * 100),避免浮點誤差。long yuan = totalFen / 100; int fen = (int)(totalFen % 100); 角 = fen/10, 分 = fen%10。
public class Rmb {
private static final String[] HAN = {"零","壹","貳","叁","肆","伍","陸","柒","捌","玖"};
private static final String[] UNIT = {"","拾","佰","仟"};
private static final String[] BIG_UNIT = {"","萬","億","兆"}; // 遞增
private double amount;
public Rmb() {}
public Rmb(double amount) { this.amount = amount; }
// 入口方法
public String toChinese() {
long totalFen = Math.round(amount * 100);
long yuan = totalFen / 100;
int fen = (int)(totalFen % 100);
if (yuan == 0 && fen == 0) return "零元整";
StringBuilder sb = new StringBuilder();
// 整數部分
if (yuan > 0) {
int groupIdx = 0;
boolean lastGroupZero = false;
while (yuan > 0) {
int group = (int)(yuan % 10000);
yuan /= 10000;
if (group > 0) {
String groupStr = convertGroup(group);
if (lastGroupZero) sb.insert(0, HAN[0]); // 補組間零
sb.insert(0, groupStr + BIG_UNIT[groupIdx]);
lastGroupZero = false;
} else {
lastGroupZero = true; // 標記本組為零,下組非零時補零
}
groupIdx++;
}
sb.append("元");
} else {
sb.append("零元");
}
// 小數部分
int jiao = fen / 10;
int fenDigit = fen % 10;
if (jiao == 0 && fenDigit == 0) {
sb.append("整");
} else {
if (jiao > 0) sb.append(HAN[jiao]).append("角");
else if (fenDigit > 0) sb.append(HAN[0]); // 如 0.05 → 零角伍分
if (fenDigit > 0) sb.append(HAN[fenDigit]).append("分");
}
return sb.toString();
}
// 4 位組內轉換
private String convertGroup(int group) { // 1~9999
StringBuilder g = new StringBuilder();
int pos = 0;
boolean zeroPending = false;
while (group > 0) {
int digit = group % 10;
group /= 10;
if (digit > 0) {
if (zeroPending) { g.insert(0, HAN[0]); zeroPending = false; }
g.insert(0, HAN[digit] + UNIT[pos]);
} else {
zeroPending = true; // 遇到零,標記待輸出
}
pos++;
}
return g.toString();
}
}
public class RmbTest {
public static void main(String[] args) throws Exception {
double[] cases = {0, 0.01, 0.1, 1.0, 10.05, 100.5, 1000.0, 12345.67, 1000000.00, 123456789.99};
for (double v : cases) {
System.out.printf("%15.2f → %s%n", v, new Rmb(v).toChinese());
}
// 交互式輸入
System.out.print("請輸入金額:");
byte[] buf = new byte[50];
System.in.read(buf);
String s = new String(buf).trim();
System.out.println(new Rmb(Double.parseDouble(s)).toChinese());
}
}
0.00 → 零元整
0.01 → 零元零壹分
0.10 → 零元壹角整
1.00 → 壹元整
10.05 → 壹拾元零伍分
100.50 → 壹佰元伍角整
1000.00 → 壹仟元整
12345.67 → 壹萬貳仟叁佰肆拾伍元陸角柒分
1000000.00 → 壹佰萬元整
123456789.99 → 壹億貳仟叁佰肆拾伍萬陸仟柒佰捌拾玖元玖角玖分
| 輸入 | 輸出 | 說明 |
|---|---|---|
| 0 / 0.0 | 零元整 | 特判 |
| 0.01 | 零元零壹分 | 角為零需輸出「零」 |
| 0.10 | 零元壹角整 | 分為零輸出「整」 |
| 1000.01 | 壹仟元零壹分 | 組內零 + 組間零 |
| 1000000 | 壹佰萬元整 | 大單位正確 |
| 999999999999.99 | 玖仟玖佰玖拾玖兆... | 支援萬億 (兆) 級 |
BigDecimal 替代 double 進行金額運算,彻底避免浮點誤差。@Component public class RmbUtil { ... }。