1. 程式人生 > >將使用者輸入的小寫貨幣形式轉換為規範的大寫貨幣形式

將使用者輸入的小寫貨幣形式轉換為規範的大寫貨幣形式

需求:寫一個程式,實現貨幣的小寫轉換成大寫形式(符合習慣)
          例如:輸入123,456,789.02返回相應的大寫 壹億貳仟叄佰肆拾伍萬陸仟柒佰捌拾玖元零貳分;
           輸入1000,返回壹仟元整;

#include "stdafx.h"
#include "math.h"
#include <string>
#include <iostream>
using namespace std;
#define INTEGER_ONLY   1    // 表示整數部分的標誌
#define DECIMAL_ONLY   2    // 表示小數部分的標誌  

/*
需求:寫一個程式,實現貨幣的小寫轉換成大寫形式(符合習慣)
      例如:輸入123,456,789.02返回相應的大寫 壹億貳仟叄佰肆拾伍萬陸仟柒佰捌拾玖元零貳分;
	        輸入1000,返回壹仟元整;
*/

/*
string類的成員函式說明:
1)
原型:double atof(const char *nptr);
功 能: 把字串轉換成浮點數
名字來源:ascii to floating point numbers 的縮寫
2) 
原型:char *fcvt(double value, int ndigit, int *decpt, int *sign);
功能: 把一個浮點數轉換為字串
引數:
  value:要轉換的浮點數,           輸入引數
  ndigit:小數點後面的位數,        輸入引數
  decpt:表示小數點的位置,          輸出引數
  sign:表示符號,0為正數,1為負數,輸出引數
3) 
原型:string replace(string src, length, replacement);  
功能:替換 src 字串中從第一個匹配src的字串索引開始的 length 個字元為 replacement 字串 
輸出:替換後的string型別
*/

/* 
*********************************************************************
功能:獲得使用者輸入的string
輸入:無
輸出:string型別
*********************************************************************
*/
string getNum() {  
    string s;  
    cout << "請輸入一個數字(精確到小數點後兩位):"<< endl;    
    cin >> s;  
    return s;  
}  

/* 
*********************************************************************
功能:將輸入的數字字串轉換為double型別,並檢查輸入的有效性(為正數)
輸入:string型別
輸出:bool型別:true,正數; false,負數
*********************************************************************
*/
bool checkNum(string& str) 
{  
	// 檢查輸入非數字的字元
	bool flag = true;
	double d = atof(str.c_str());   //把字串轉換成浮點數
	if(d < 0)
		flag = false;	
	return flag;
} 
/*
*********************************************************************
功能:將這個數轉換成 double 型別,並對其進行四捨五入操作  
輸入:string型別
輸出:string型別
*********************************************************************
*/
string roundString(string s) 
{  
    double d = atof(s.c_str());       /* 轉換成 double 型別                         */
    int dec, sign;                    /* fcvt()函式輸出引數                         */ 
    s = fcvt(d, 2, &dec, &sign);      /*  將這個數進行四捨五入,保留到小數點後兩位; 
					    當這個數轉換成字串以後不會顯示小數點,
				          並且會以四捨五入的形式只保留小數點後兩位  */
								                
    if(s.length() > 15)               /* 規定數值的最大長度只能是15位(到萬億位)   */
	{  
        cout << "提示:輸入資料過大!(整數部分最多13位!)"<< endl;  
        return "";  
    }  
    return s;  
} 

/*
*********************************************************************
功能:將這個數轉換成 double 型別,並對其進行四捨五入操作  
輸入:標誌位flag,string型別
輸出:string型別
*********************************************************************
*/   
string formatChinese(int flag, string s) {  
    int sLength = s.length();   
    string bigLetter[] = {"零","壹","貳","叄","肆","伍","陸","柒","捌","玖"};  /* 貨幣大寫形式   */  
    string small[]     = {"分", "角"};                                         /*分位到角位      */
	string unit[]  = {"元", "拾", "佰", "仟",                              /*個位到仟位      */  
                          "萬", "拾", "佰", "仟",                              /*拾萬位到仟萬位  */     
                          "億", "拾", "佰", "仟", "萬"};                       /*億位到萬億位    */  
 
    string newS = "";                          /* 用來存放轉換後的新字串             */   
    for(int i = 0; i < sLength; i ++)          /* 逐位替換為中文大寫形式               */
	{  
        if(flag == INTEGER_ONLY)               /* 轉換整數部分為中文大寫形式(帶單位) */
		{                         
            newS = newS + bigLetter[s.at(i) - '0'] + unit[sLength-1 - i];  
        } 
		else if(flag == DECIMAL_ONLY)  /* 轉換小數部分(帶單位)               */
		{       
            newS = newS + bigLetter[s.at(i) - '0'] + small[sLength-1 - i];  
        }  
    }  
    return newS;  
}  
  
/*
*********************************************************************
功能:將這個數分割成整數部分和小數部分,轉換成對應的貨幣的中文大寫形式  
輸入:string型別
輸出:string型別
*********************************************************************
*/  
string splitNum(string s) 
{  
    if("" == s)                                      /* 如果傳入的是空串則繼續返回空串  */
	{  
        return "";  
    }  
    string IntegerOnly = s.substr(0, s.size() - 2);  /* 擷取輸入數字的整數部分          */
    string IntegerPart = formatChinese(INTEGER_ONLY, IntegerOnly);  
    
    string DecimalOnly = s.substr(s.size() - 2, s.size()); /* 擷取這個數的小數部分      */
    string DecimalPart = formatChinese(DECIMAL_ONLY, DecimalOnly);  
    
    string newS = IntegerPart + DecimalPart;       /* 把轉換好了的整數部分和小數部...
						       ...分重新拼湊一個新的字串      */    
    return newS;  
}  
  
/*
*********************************************************************
功能:將非規範性貨幣中文大寫表達形式轉換成規範的貨幣中文大寫形式  
輸入:string型別(source),string型別(搜尋字串),string型別(替代字串)
輸出:string型別
*********************************************************************
*/   
string replaceAll(string src, string regex, string replacement) {  
    int length = regex.length();  
    while(src.find(regex) < src.length()) 
	{  
        src.replace(src.find(regex), length, replacement);  
    }  
    return src;  
}  

/*
*********************************************************************
功能:將非規範性貨幣中文大寫表達形式轉換成規範的貨幣中文大寫形式  
輸入:string型別
輸出:string型別
*********************************************************************
*/  
string cleanZero(string s) 
{     
    if("" == s)                           /* 如果傳入的是空串則返回空串 */
	{  
        return "";  
    }  
    string regex1[] = {"零仟", "零佰", "零拾"};  
    string regex2[] = {"零億", "零萬", "零元"};  
    string regex3[] = {"億", "萬", "元"};  
    string regex4[] = {"零角", "零分"};  
    
	// 字串中存在多個'零'在一起的時候只讀出一個'零',並省略多餘的單位  	
    for(int i = 0; i < 3; i ++){           /* case1: 把 "零仟", 零佰","零拾"...
					   ...等字串替換成一個"零"               */ 
        s = replaceAll(s, regex1[i], "零"); 
    }  
    s = replaceAll(s, "零零零", "零");  
    s = replaceAll(s, "零零", "零");       /* 當第一輪轉換過後有可能有很多個零疊在一起,  
                                        ...要把很多個重複的零變成一個零            */  
      
    for(int i = 0; i < 3; i ++)            /* 第二輪轉換考慮 "零億","零萬","零元"等情況 */
	{                       
        s = replaceAll(s, regex2[i], regex3[i]);  /* "億","萬","元"這些單位有些情況是...
				          ...不能省的,需要保留下來                */
    }  
    s = replaceAll(s,"零角零分","整");     /* 考慮沒有小數的情況                   */
    for(int i = 0; i < 2; i ++) {          /* 第三輪轉換把"零角","零分"字串省略  */
        s = replaceAll(s, regex4[i], "");  
    }  
    
    s = replaceAll(s, "億萬", "億");       /* 當"萬"到"億"之間全部是"零"的時候,
					  ...忽略"億萬"單位,只保留一個"億"        */
    return s;  
}  

int _tmain(int argc, _TCHAR* argv[])
{
	cout << "\n------------將數字轉換成中文金額的大寫形式(C++)------------\n" << endl;    
    for(;;)
	{
		string s = getNum();  
		if(checkNum(s))              /* 檢查使用者輸入是否有效                     */
		{   
			s = roundString(s);  /* 用四捨五入規範浮點數,保留兩位           */       
			s = splitNum(s);     /* 把浮點數分割成小數和整數部分,分別表示為...
			                       ...貨幣的大寫形式                         */
			s = cleanZero(s);    /* 把貨幣的大寫形式規範化                   */
			cout << "轉換成中文後為:" << s << endl;  
		} 
		else 
		{  
			cout << "非法輸入,程式即將退出" << endl;  
		}  
		cout << "\n--------------------------------------------------------------" << endl; 
	}
	return 0;
}

輸出結果: