核心演算法邏輯
- 分離整數部分與小數部分(角、分)
- 整數部分按 4 位一組分段(萬、億),段內按千/百/十/個處理
- 零處理規則:段內連續零只輸出一個「零」;段末為零不輸出單位;最高段為零不輸出
- 小數部分:角、分為零時分別處理「整」字
完整可用代碼
CString NumberToRMB(CString strNumber)
{
// 1. 預處理:分離整數/小數
int nDotPos = strNumber.Find(_T('.'));
CString strInt, strDec;
if (nDotPos != -1)
{
strInt = strNumber.Left(nDotPos);
strDec = strNumber.Mid(nDotPos + 1);
if (strDec.GetLength() > 2) strDec = strDec.Left(2); // 保留兩位
while (strDec.GetLength() < 2) strDec += _T('0'); // 補齊兩位
}
else
{
strInt = strNumber;
strDec = _T("00");
}
// 去除整數部分前導零
strInt.TrimLeft(_T('0'));
if (strInt.IsEmpty()) strInt = _T("0");
// 2. 定義常量
const TCHAR* szDigit = _T("零壹貳叁肆伍陸柒捌玖");
const TCHAR* szUnit1 = _T("拾佰仟"); // 段內單位
const TCHAR* szUnit2 = _T("萬億兆"); // 段單位(每4位)
CString strResult;
// 3. 處理整數部分(從低位向高位,每4位一段)
int nLen = strInt.GetLength();
int nSegCount = (nLen + 3) / 4; // 段數
for (int nSeg = 0; nSeg < nSegCount; ++nSeg)
{
// 提取當前段 (低位在前)
int nStart = nLen - (nSeg + 1) * 4;
if (nStart < 0) nStart = 0;
int nSegLen = nLen - nSeg * 4 - nStart;
CString strSeg = strInt.Mid(nStart, nSegLen);
// 段內處理
CString strSegResult;
bool bLastZero = false;
for (int i = 0; i < strSeg.GetLength(); ++i)
{
int nDigit = strSeg[i] - _T('0');
int nPosInSeg = strSeg.GetLength() - 1 - i; // 0=個, 1=十, 2=百, 3=千
if (nDigit == 0)
{
if (!bLastZero && i != strSeg.GetLength() - 1) // 非末位零
strSegResult += szDigit[0]; // "零"
bLastZero = true;
}
else
{
strSegResult += szDigit[nDigit];
if (nPosInSeg > 0) strSegResult += szUnit1[nPosInSeg - 1];
bLastZero = false;
}
}
// 段結果非空則加段單位
if (!strSegResult.IsEmpty())
{
if (nSeg > 0) strSegResult += szUnit2[nSeg - 1];
strResult = strSegResult + strResult; // 高段在前
}
}
// 4. 處理小數部分(角、分)
CString strDecResult;
int nJiao = strDec[0] - _T('0');
int nFen = strDec[1] - _T('0');
if (nJiao > 0) strDecResult.Format(_T("%c角"), szDigit[nJiao]);
if (nFen > 0) strDecResult.AppendFormat(_T("%c分"), szDigit[nFen]);
// 5. 組合最終結果
if (strResult.IsEmpty()) strResult = _T("零");
strResult += _T("元");
if (strDecResult.IsEmpty())
strResult += _T("整");
else
strResult += strDecResult;
return strResult;
}
測試用例對照表
| 輸入 | 輸出 | 說明 |
0 | 零元整 | 零值處理 |
10 | 壹拾元整 | 十位非零 |
101 | 壹佰零壹元整 | 中間零 |
1001 | 壹仟零壹元整 | 連續零只一個 |
10001 | 壹萬零壹元整 | 跨段零 |
123456789.45 | 壹億貳仟叁佰肆拾伍萬陸仟柒佰捌拾玖元肆角伍分 | 完整大數 |
100.05 | 壹佰元零伍分 | 角為零 |
0.10 | 零元壹角整 | 純小數 |
關鍵細節說明
- 段內逆序處理:從個位向千位,便於判斷「末位零」不輸出
- bLastZero 標誌:避免連續輸出多個「零」
- 段結果前綴拼接:
strResult = strSegResult + strResult 實現高段在前
- 「整」字規則:角分皆為零 → 輸出「整」;角為零分非零 → 輸出「零X分」;角非零分為零 → 輸出「X角整」
- 擴展性:
szUnit2 可續接「京、垓、秭...」支持更大數值
調用示例
void CMyDialog::OnButtonConvert()
{
UpdateData(TRUE);
CString strRMB = NumberToRMB(m_strInputNumber);
m_strOutputRMB = strRMB;
UpdateData(FALSE);
}