最近在网上看到一个关于数字转换人民币大写的算法的一篇博客,很好,就收藏了,算法直接copy原作者的。自己做了一点小改动:
1.以CString代替,封装成类。
2.修复超过"亿"时显示"亿万"的bug。
3.扩大检索范围至"千万亿(lg16)"。
如果各位有更好的算法,多贡献出来大家研究研究,废话补多说,直接贴出来供大家参考!
算法转载作者博客为:http://www.cnblogs.com/jingmoxukong/p/3821339.html
// numberConvert.h
#ifndef _NUMBERCONVERT_H_
#define _NUMBERCONVERT_H_
#include <atlstr.h>
#include <CString>
#include <String>
#ifndef ArrayCount
#define ArrayCount(Array) (sizeof(Array)/sizeof(Array[0]))
#endif // ArrayCount
#ifndef SAFE_DELETE
# define SAFE_DELETE(p) { try { delete p; } catch (...) { } p = nullptr; }
#endif // SAFE_DELETE
#ifndef SAFE_DELETE_ARRAY
# define SAFE_DELETE_ARRAY(pArr) { if (pArr) { delete [] (pArr); (pArr) = nullptr; } }
#endif // SAFE_DELETE_ARRAY
using namespace std;
class NumberConvert
{
public:
NumberConvert();
~NumberConvert();
// 将源字符串strOrig中第一个匹配strSub的子串部分替换为strReplace
int ReplaceSubStr(CString &strOrig, CString strSub, CString strReplace);
// 将人民币double数值转化为人民币汉字CString
CString NumToChineseStr(double money);
private:
CString* m_pstrDigit;
CString* m_pstrUnit1;
CString* m_pstrUnit2;
};
#endif //_NUMBERCONVERT_H_
// numberConvert.cpp
#include "numberConvert.h"
NumberConvert::NumberConvert()
{
CString strDigit[] = { _T("零"), _T("壹"), _T("贰"), _T("叁"), _T("肆")
, _T("伍"), _T("陆"), _T("柒"), _T("捌"), _T("玖") };
CString strUnit[] = { _T("圆"), _T("拾"), _T("佰"), _T("仟"), _T("万")
, _T("拾"), _T("佰"), _T("仟"), _T("亿")
, _T("拾"), _T("佰"), _T("仟"), _T("万"), _T("拾"), _T("佰"), _T("仟") };
CString strUnit2[] = { _T("角"), _T("分") };
int iLen = ArrayCount(strDigit);
m_pstrDigit = new CString[iLen];
for (int i = 0; i < iLen; ++i)
{
m_pstrDigit[i] = strDigit[i];
}
iLen = ArrayCount(strUnit);
m_pstrUnit1 = new CString[iLen];
for (int i = 0; i < iLen; ++i)
{
m_pstrUnit1[i] = strUnit[i];
}
iLen = ArrayCount(strUnit2);
m_pstrUnit2 = new CString[iLen];
for (int i = 0; i < iLen; ++i)
{
m_pstrUnit2[i] = strUnit2[i];
}
}
NumberConvert::~NumberConvert()
{
SAFE_DELETE_ARRAY(m_pstrDigit);
SAFE_DELETE_ARRAY(m_pstrUnit1);
SAFE_DELETE_ARRAY(m_pstrUnit2);
}
int NumberConvert::ReplaceSubStr(CString &strOrig, CString strSub, CString strReplace)
{
int pos = (int)strOrig.Find(strSub);
if (pos >= 0)
{
strOrig.Replace(strSub, strReplace);
return 0;
}
return -1;
}
CString NumberConvert::NumToChineseStr(double money)
{
int i = 0;
int ret = 0;
int length = 0;
char *p = NULL;
char *pcDecimal = NULL; //保存小数部分字符
char czNumber[MAX_PATH] = { 0 }; //保存完整数字部分字符
CString strResult;
//判断是否为小数
if (money < 0)
{
strResult += _T("负");
money = ::abs(money);
}
//将数字转为数字字符串,利用sprintf_s的正则转换
_stprintf_s(czNumber, MAX_PATH, _T("%.16lg"), money);
//如果数字是太大或太小的数,因为已经转为科学计数,所以会含有e字符
p = _tcschr(czNumber, _T('e'));
if (NULL != p)
{
strResult = _T("金额超出计算范畴");
return strResult;
}
p = _tcschr(czNumber, _T('.'));
if (NULL != p)
{
p[0] = 0;
pcDecimal = p + 1;
}
length = (int)_tcslen(czNumber);
for (i = 0; i < length; ++i)
{
if (_T('0') == czNumber[i] && 0 != ((length - 1 - i) % 4))
{
strResult += m_pstrDigit[czNumber[i] - _T('0')];
}
else
{
strResult += m_pstrDigit[czNumber[i] - _T('0')] + m_pstrUnit1[length - i - 1];
}
}
//把strResult中的所有"零零"子串替换为"零"
while (true)
{
ret = ReplaceSubStr(strResult, _T("零零"), _T("零"));
if (ret < 0)
{
break;
}
}
ReplaceSubStr(strResult, _T("零亿"), _T("亿"));
ReplaceSubStr(strResult, _T("零万"), _T("万"));
ReplaceSubStr(strResult, _T("亿万"), _T("亿"));
//如果整数部分全为0,则不要去除元单位前面的零
if (_tcscmp(strResult, _T("零圆")) != 0)
{
ReplaceSubStr(strResult, _T("零圆"), _T("圆"));
}
//小数精确到两位数,即精确到单位分
if (NULL != pcDecimal)
{
//如果小数部分有数值而整数部分为0,则删除字符串中的零元
if (_tcscmp(strResult, _T("零圆")) == 0
|| _tcscmp(strResult, _T("零")) == 0)
{
strResult.Empty();
}
i = 0;
while (true)
{
if (0 == pcDecimal[i] || i >= 2)
{
break;
}
strResult += m_pstrDigit[pcDecimal[i] - _T('0')] + m_pstrUnit2[i];
++i;
}
}
// 剔除掉"圆"字
strResult.Replace(_T("圆"), _T(""));
return strResult;
}