1. 程式人生 > >[演算法題] 人民幣大小寫轉換(阿拉伯數字和漢字轉換)

[演算法題] 人民幣大小寫轉換(阿拉伯數字和漢字轉換)

在一次面試中遇到一個有意思的小演算法題:要求將阿拉伯數字轉為漢字顯示出來(包含單位)。

當時雖然實現出來,但是程式碼寫的有點凌亂。所以回家後,重新整理了一下。

這個演算法有幾個小的注意點:

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;
}

結果