在一次面試中遇到一個有意思的小算法題:要求將阿拉伯數字轉為漢字顯示出來(包含單位)。
當時雖然實現出來,但是代碼寫的有點凌亂。所以回家后,重新整理了一下。
這個算法有幾個小的注意點:
1、中文字符占兩個字節,所以如果用C語言實現,需要用char數組的形式保存單個漢字。
2、如果數字中出現連續的零,需要把它替換為單一的零。
3、在億、萬、元的前面一個漢字不可以為零(人民幣讀取方式決定)。
4、double數值可分為整數部分和小數部分。小數部分較簡單,整數部分需要根據這個數字所在的位數匹配上對應的單位。
具體方法是:設置一個單位映射字符串表g_strUnit,可視為一個簡單的HashTable。然后從頭開始讀取整數字符串的每個
字符,若這個字符在整數字符串的位置為i,這個字符后面的單位就是g_strUnit[length-1-i]。
代碼如下
/*
******************************************************************************
Project Code : Account
File name :
Author : Latte
Description : 阿拉伯數字轉為中文字符串
Function List :
--------------------------------------------------------------------------------
History:
Date Author Modification
20140703 Latte created file.
****************************************************************************** */
#include " stdafx.h "
#include < string>
#include <iostream>
using namespace std;
#define MAX 100
string g_strDigit[] = { " 零 ", " 壹 ", " 貳 ", " 叄 ", " 肆 ", " 伍 ", " 陸 ", " 柒 ", " 捌 ", " 玖 "};
string g_strUnit[] = { " 圓 ", " 拾 ", " 佰 ", " 仟 ", " 萬 ", " 拾 ", " 佰 ", " 仟 ", " 億 ",
" 拾 ", " 佰 ", " 仟 ", " 萬 ", " 拾 ", " 佰 "};
string g_strUnit2[] = { " 角 ", " 分 "};
/* ******************************************************************************
Func Name : ReplaceSubStr
Date Created : 2014-07-03
Author : Latte
Description : 將源字符串strOrig中第一個匹配strSub的子串部分替換為strReplace
Input :
string &strOrig,
string strSub,
string strReplace
Output :
string &strOrig
Return :
int
Caution : 返回值如果為-1,則表示替換失敗或未找到替換項
****************************************************************************** */
int ReplaceSubStr( string &strOrig, string strSub, string strReplace)
{
int pos = ( int)strOrig.find(strSub);
int length = ( int)strSub.length();
if (pos >= 0)
{
strOrig.replace(pos, length, strReplace);
return 0;
}
return - 1;
}
/* ******************************************************************************
Func Name : NumToChineseStr
Date Created : 2014-07-03
Author : Latte
Description :
將人民幣double數值轉化為人民幣漢字string
Input :
double money
Output :
Return :
string
Caution :
****************************************************************************** */
string NumToChineseStr( double money)
{
int i = 0;
int ret = 0;
int length = 0;
char *p = NULL;
char *pcDecimal = NULL; // 保存小數部分字符
char czNumber[MAX] = { 0}; // 保存完整數字部分字符
string strResult;
cout << " ====================================== " << endl;
cout << money << endl;
// 判斷是否為小數
if (money < 0)
{
strResult = " 不支持讀負數 ";
return strResult;
}
// 將數字轉為數字字符串,利用sprintf_s的正則轉換
sprintf_s(czNumber, MAX, " %.15lg ", money);
printf( " [No.0]%s\n ", czNumber);
// 如果數字是太大或太小的數,因為已經轉為科學計數,所以會含有e字符
p = strchr(czNumber, ' e ');
if (NULL!=p)
{
strResult = " 不支持讀太大或太小的數 ";
return strResult;
}
p = strchr(czNumber, ' . ');
if (NULL != p)
{
p[ 0] = 0;
pcDecimal = p + 1;
}
length = ( int)strlen(czNumber);
for (i = 0; i<length; i++)
{
if ( ' 0 ' == czNumber[i] && 0 != ((length- 1-i) % 4))
{
strResult += g_strDigit[czNumber[i] - ' 0 '];
}
else
{
strResult += g_strDigit[czNumber[i] - ' 0 '] + g_strUnit[length- 1-i];
}
}
cout << " [No.1]把數字直接替換為漢字: \n " << strResult << endl;
// 把strResult中的所有"零零"子串替換為"零"
while ( 1)
{
ret = ReplaceSubStr(strResult, " 零零 ", " 零 ");
if (ret < 0)
{
break;
}
}
cout << " [No.2]替換所有零零為零: \n " << strResult << endl;
ReplaceSubStr(strResult, " 零億 ", " 億 ");
ReplaceSubStr(strResult, " 零萬 ", " 萬 ");
if (strResult != " 零圓 ") // 如果整數部分全為0,則不要去除元單位前面的零
{
ReplaceSubStr(strResult, " 零圓 ", " 圓 ");
}
cout << " [No.3]去除零億、零萬、零圓前面的零: \n " << strResult << endl;
// 小數精確到兩位數,即精確到單位分
if (NULL != pcDecimal)
{
// 如果小數部分有數值而整數部分為0,則刪除字符串中的零元
if (strResult == " 零圓 ")
{
strResult.clear();
}
i = 0;
while ( 1)
{
if ( 0 == pcDecimal[i] || i >= 2)
break;
strResult += g_strDigit[pcDecimal[i] - ' 0 '] + g_strUnit2[i];
i++;
}
}
cout << " [No.4]小數精確到兩位數,即精確到單位分: \n " << strResult << endl;
return strResult;
}
int main( void)
{
// cout << "Result: " << NumToChineseStr(0.00) << endl;
// cout << "Result: " << NumToChineseStr(-345.67) << endl;
// cout << "Result: " << NumToChineseStr(1000.0) << endl;
cout << " Result: " << NumToChineseStr( 130040600090.012) << endl;
return 0;
}
Project Code : Account
File name :
Author : Latte
Description : 阿拉伯數字轉為中文字符串
Function List :
--------------------------------------------------------------------------------
History:
Date Author Modification
20140703 Latte created file.
****************************************************************************** */
#include " stdafx.h "
#include < string>
#include <iostream>
using namespace std;
#define MAX 100
string g_strDigit[] = { " 零 ", " 壹 ", " 貳 ", " 叄 ", " 肆 ", " 伍 ", " 陸 ", " 柒 ", " 捌 ", " 玖 "};
string g_strUnit[] = { " 圓 ", " 拾 ", " 佰 ", " 仟 ", " 萬 ", " 拾 ", " 佰 ", " 仟 ", " 億 ",
" 拾 ", " 佰 ", " 仟 ", " 萬 ", " 拾 ", " 佰 "};
string g_strUnit2[] = { " 角 ", " 分 "};
/* ******************************************************************************
Func Name : ReplaceSubStr
Date Created : 2014-07-03
Author : Latte
Description : 將源字符串strOrig中第一個匹配strSub的子串部分替換為strReplace
Input :
string &strOrig,
string strSub,
string strReplace
Output :
string &strOrig
Return :
int
Caution : 返回值如果為-1,則表示替換失敗或未找到替換項
****************************************************************************** */
int ReplaceSubStr( string &strOrig, string strSub, string strReplace)
{
int pos = ( int)strOrig.find(strSub);
int length = ( int)strSub.length();
if (pos >= 0)
{
strOrig.replace(pos, length, strReplace);
return 0;
}
return - 1;
}
/* ******************************************************************************
Func Name : NumToChineseStr
Date Created : 2014-07-03
Author : Latte
Description :
將人民幣double數值轉化為人民幣漢字string
Input :
double money
Output :
Return :
string
Caution :
****************************************************************************** */
string NumToChineseStr( double money)
{
int i = 0;
int ret = 0;
int length = 0;
char *p = NULL;
char *pcDecimal = NULL; // 保存小數部分字符
char czNumber[MAX] = { 0}; // 保存完整數字部分字符
string strResult;
cout << " ====================================== " << endl;
cout << money << endl;
// 判斷是否為小數
if (money < 0)
{
strResult = " 不支持讀負數 ";
return strResult;
}
// 將數字轉為數字字符串,利用sprintf_s的正則轉換
sprintf_s(czNumber, MAX, " %.15lg ", money);
printf( " [No.0]%s\n ", czNumber);
// 如果數字是太大或太小的數,因為已經轉為科學計數,所以會含有e字符
p = strchr(czNumber, ' e ');
if (NULL!=p)
{
strResult = " 不支持讀太大或太小的數 ";
return strResult;
}
p = strchr(czNumber, ' . ');
if (NULL != p)
{
p[ 0] = 0;
pcDecimal = p + 1;
}
length = ( int)strlen(czNumber);
for (i = 0; i<length; i++)
{
if ( ' 0 ' == czNumber[i] && 0 != ((length- 1-i) % 4))
{
strResult += g_strDigit[czNumber[i] - ' 0 '];
}
else
{
strResult += g_strDigit[czNumber[i] - ' 0 '] + g_strUnit[length- 1-i];
}
}
cout << " [No.1]把數字直接替換為漢字: \n " << strResult << endl;
// 把strResult中的所有"零零"子串替換為"零"
while ( 1)
{
ret = ReplaceSubStr(strResult, " 零零 ", " 零 ");
if (ret < 0)
{
break;
}
}
cout << " [No.2]替換所有零零為零: \n " << strResult << endl;
ReplaceSubStr(strResult, " 零億 ", " 億 ");
ReplaceSubStr(strResult, " 零萬 ", " 萬 ");
if (strResult != " 零圓 ") // 如果整數部分全為0,則不要去除元單位前面的零
{
ReplaceSubStr(strResult, " 零圓 ", " 圓 ");
}
cout << " [No.3]去除零億、零萬、零圓前面的零: \n " << strResult << endl;
// 小數精確到兩位數,即精確到單位分
if (NULL != pcDecimal)
{
// 如果小數部分有數值而整數部分為0,則刪除字符串中的零元
if (strResult == " 零圓 ")
{
strResult.clear();
}
i = 0;
while ( 1)
{
if ( 0 == pcDecimal[i] || i >= 2)
break;
strResult += g_strDigit[pcDecimal[i] - ' 0 '] + g_strUnit2[i];
i++;
}
}
cout << " [No.4]小數精確到兩位數,即精確到單位分: \n " << strResult << endl;
return strResult;
}
int main( void)
{
// cout << "Result: " << NumToChineseStr(0.00) << endl;
// cout << "Result: " << NumToChineseStr(-345.67) << endl;
// cout << "Result: " << NumToChineseStr(1000.0) << endl;
cout << " Result: " << NumToChineseStr( 130040600090.012) << endl;
return 0;
}
結果