小寫轉大寫金額在C++中的實現 (轉)

amyz發表於2007-08-14
小寫轉大寫金額在C++中的實現 (轉)[@more@]

在小寫轉大寫金額時我們應該注意的是人類在讀數的過程進行分析,比如要讀“12345.67”,大寫讀法是:“壹萬貳仟叄佰肆拾伍元陸角柒分”,在實際的讀數過程中,人必須知道1後面有4位,即是萬,2後面有3位,即是仟,依次類推,當然由於人已經習慣了萬的下一位是仟,所以不再去數2的後面有幾位。

根據上面的識別過程,我們應該採取反相識別實現遇到的數字,即在讀取整數部份時,應是“伍肆拾叄佰貳仟壹萬”。

另外接零的方式與段的設定,

1.  零主要存在於兩個數之間有0的情況,但“拾”位情況除外,如拾萬伍仟,因為在大寫裡面不會念拾萬零伍仟,所以這裡要特殊處理。

2.  所謂段,中國人的習慣與西方的習慣不同,西方的數字是以千計,而我們的習慣是以萬計,即該段與更高一段之間沒有非零數字,則這個段名不必讀,如壹億零伍仟,其中的萬也就不讀了。

下面提供實現的程式碼及註釋

CString GetBigMoney(double dMoney):namespace prefix = o ns = "urn:schemas--com::office" />

  //這裡沒有對超出部份作異常,使用者要注意(現實中不會出現如此巨大的金額數)

  CString strMoney;

  strMoney.Format ("%.2f" , dMoney);

  CString strUnit = "元拾佰仟萬拾佰仟億拾佰仟";

  CString strNumber = "零壹貳叄肆伍陸柒捌玖";

  CString strOtherUnit = "整角分";

 

  //將數字分整數部份與小數部份處理

  int nP= 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 --)

  {

  TCHAR ch = strMoney.GetAt (i);

  if(nCount % 4 == 0 && nCount > 0)

  {

      //如果處理的數字為第四位(萬),或第八位(億)等,則要求置段

  bNeedLevel = true;

  }

  if(ch == '0')

  {

      //只對拾佰仟位的0進行識別,主要考慮到拾的特殊性,即如10讀壹拾,不會讀壹拾零

  if(nCount % 4 != 0)

  bZero = true;

  }

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

  }

  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

  {

    //對分角的處理

  for(int i = 0;i < nLength;i ++)

  {

  TCHAR ch = strMoney.GetAt (nPos + 1 + i);

  if(ch == '0' && i > 0)

  {

  }

  else

  {

  strReturnValue += strNumber.Mid ((ch - 0x30) * 2 , 2);

  if(ch != '0')

  strReturnValue += strOtherUnit.Mid ((i + 1) * 2 , 2);

  }

  }

  }

  return strReturnValue;

點評:小寫轉大寫金額中,根據理解,我們可以將一個數分成兩個層次處理,即段間處理與段內處理,段內處理即為對於小於10,000的數字的轉換,段間處理則在段內處理的基礎上再進行處理,顯然遞迴是一種可行的演算法(參閱/Develop/read_article.?id=18342" target=_blank>遞迴在C++應用中的利與弊),實現起來可能會簡單些。

本演算法是筆者在急需要類似演算法時寫下的,只有參考價值,並無直接應用的實踐價值,讀者可以對此修改後使用。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-956494/,如需轉載,請註明出處,否則將追究法律責任。

相關文章