成熟稳定的数字转换为汉字金额大写文字函数

在开发Grid++Report报表工具的过程中,需要一个将数字转换为汉字金额大写文字的函数。在网上也搜索到了一些朋友奉献的作品,但仔细查阅之后都有一些不足。最后没有办法,只好综合各方的思路再次做了重新发明轮子的事。整个函数还是比较复杂,但有Grid++Report庞大用户群的考验,可以保证这个转换汉字金额大写的函数是成熟稳定高效的。在此奉献出来,希望能帮到需要的朋友,免除不必要的做重新发明轮子的苦差。

代码是用VC++写的,如下:


#include "stdafx.h"
#include <string>
#include <atlstr.h>

using namespace std;
using namespace ATL;

const char Const_Str_ZeroYuan[] = "零元整";
const char Const_Str_BigAmtNumber[] = "零壹贰叁肆伍陆柒捌玖";
const char Const_Str_HZNegative[] = "负";
const CString strUnit = "元拾佰仟万拾佰仟亿拾佰仟";
const CString strNumber = Const_Str_BigAmtNumber;
const CString strOtherUnit = "整角分";

string ToBigMoney(double dMoney)
{
 const double ZeroLowRange = -0.005; //-0.004449;
 const double ZeroHighRange = 0.005; //0.004449;
 if (ZeroLowRange < dMoney && dMoney < ZeroHighRange)
  return Const_Str_ZeroYuan; //"零元整";

 bool Negative = FALSE;
 if (dMoney <= ZeroLowRange)
 {
  Negative = TRUE;
  dMoney = -dMoney;
 }

 //这里没有对超出部份作异常,使用者要注意(现实中不会出现如此巨大的金额数)
     CString strMoney;
     strMoney.Format ("%.2f" , dMoney);

     //将数字分整数部份与小数部份处理
     int nPos = strMoney.Find (".");
     int nLength = strMoney.GetLength ();
     if(nPos < 0)
         nPos = nLength;

     CString strReturnValue;
     int nCount = 0;
     bool bZero = false;
     bool bNeedLevel = false;    //对段的识别,用于是否需要出现段名,如亿,万等

     //对整数部份进行反相识别处理
     for(int i = nPos - 1;i >= 0;i --)
     {
         char ch = strMoney.GetAt (i);

  if(nCount % 4 == 0 && nCount > 0)
        {
               //如果处理的数字为第四位(万),或第八位(亿)等,则要求置段
              bNeedLevel = true;
        }

        if(ch == '0')
        {
   //只对拾佰仟位的0进行识别,主要考虑到拾的特殊性,即如10读壹拾,不会读壹拾零
   //if(nCount % 4 != 0)
   //   bZero = true;
   bZero = true; //去掉%4判断, 让 102000 读做:壹拾万零贰仟元整。9,050,155,001-〉玖拾亿零伍仟零壹拾伍万伍仟零壹元整
        }
        else
        {
              CString strTemp(strReturnValue);
              strReturnValue = strNumber.Mid ((ch - 0x30) * 2 , 2);

              if(nCount > 0)
              {
                  strReturnValue += strUnit.Mid (nCount * 2 , 2);
                  if(nCount % 4 != 0 && bNeedLevel)
                  {
                         //这里判断是否需要读段名,如万,亿等
                       strReturnValue += strUnit.Mid (int(nCount / 4) * 8 , 2);
                  }
                  bNeedLevel = false;
              }

              if(bZero)
              {
                   //只有比当前处理的位要低中有数字才补零
                   if( !strTemp.IsEmpty () )
                       strReturnValue += strNumber.Left (2);
                   bZero = false;
              }

              strReturnValue += strTemp;
         }

         nCount ++;
     }

  //如果没有整数部分,则不用加元
  if ( !strReturnValue.IsEmpty() )
  strReturnValue += strUnit.Left (2);


     //下面实现对小数点后面的处理, 先判断是否为全零,则不需要继续读
     bool bAllZero = true;
     if(nPos < nLength)
     {
         if(nLength > 2)
              nLength = 2;
         for(int i = 0;i < nLength;i ++)
              if(strMoney.GetAt (nPos + i + 1) != '0')
                   bAllZero = false;
     }

     if(bAllZero)
     {
         strReturnValue += strOtherUnit.Left (2);
     }
     else
     {
        //对角的处理,如果没有整数部分,则不用加上零角的零
        char ch = strMoney.GetAt (nPos + 1);
        if(ch != '0' || !strReturnValue.IsEmpty())
   strReturnValue += strNumber.Mid ((ch - 0x30) * 2 , 2);
  if(ch != '0')
   strReturnValue += strOtherUnit.Mid (1 * 2 , 2);
 
        //对分的处理,如果没有分,角后加‘整’
        ch = strMoney.GetAt (nPos + 1 + 1);
  if(ch != '0')
  {
   strReturnValue += strNumber.Mid ((ch - 0x30) * 2 , 2);
   strReturnValue += strOtherUnit.Mid (2 * 2 , 2);
  }
  else
  {
   strReturnValue += strOtherUnit.Left (2);
  }
     }

 if (Negative)
  strReturnValue = Const_Str_HZNegative + strReturnValue;

 return string(strReturnValue);
}

posted on 2008-07-12 21:14  报表工具研究  阅读(1606)  评论(1编辑  收藏  举报

导航