熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

C#純數學方法遞歸實現貨幣數字轉換中文

2013-11-13 10:15:46  來源: .NET編程 

  最近由於項目的原因需要寫一個貨幣數字轉換中文的算法先在網了找了一下結果發現無一列外都是用(Replace)替換的方式來實現的所以想寫個另外的算法因為本人是學數學出身的所以用純數學的方法實現

  注意本文中的算法支持小於 (也就是億兆)貨幣數字轉化

  貨幣中文說明 在說明代碼之前首先讓我們回顧一下貨幣的讀法

    讀為 壹仟零貳萬零貳元貳角三分
           讀為 壹仟零貳拾元整
         讀為 拾萬元整
           讀為 壹角三分

  

  代碼

  測試工程
  static void Main(string[] args)
{

  ConsoleWriteLine(請輸入金額);
string inputNum = ConsoleReadLine();
while (inputNum != exit)
{

  //貨幣數字轉化類
NumCast nc = new NumCast();

  if (ncIsValidated<string>(inputNum))
{
try
{
string chineseCharacter = ncConvertToChinese(inputNum);
ConsoleWriteLine(chineseCharacter);
}
catch (Exception er)
{
ConsoleWriteLine(erMessage);
}
}
else
{
ConsoleWriteLine(不合法的數字或格式);
}

  ConsoleWriteLine(\n請輸入金額);
inputNum = ConsoleReadLine();

  }
ConsoleReadLine();
}

  測試結果如下

  貨幣轉化類(NumCast類)功能介紹

   常量的規定
 /// <summary>
/// 數位
/// </summary>
public enum NumLevel { Cent Chiao Yuan Ten Hundred Thousand TenThousand hundredMillon Trillion };

  /// <summary>
/// 數位的指數
/// </summary>
private int[] NumLevelExponent = new int[] { };

  /// <summary>
/// 數位的中文字符
/// </summary>
private string[] NumLeverChineseSign = new string[] { };

  /// <summary>
/// 大寫字符
/// </summary>
private string[] NumChineseCharacter = new string[] {};

  /// <summary>
/// 整(當沒有 角分 時)
/// </summary>

  private const string EndOfInt = ;

  數字合法性驗證采用正則表達式驗證
 /// <summary>
/// 正則表達驗證數字是否合法
/// </summary>
/// <param name=Num></param>
/// <returns></returns>
public bool IsValidated<T>(T Num)
{
Regex reg = new Regex(@^(([])|([]\d{}))(\\d{})?$);
if (regIsMatch(NumToString()))
{
return true;

  }
return false;
}

   獲取數位 例如 的數位為 NumLevelThousand

  /// <summary>
/// 獲取數字的數位 使用log
/// </summary>
/// <param name=Num></param>
/// <returns></returns>
private NumLevel GetNumLevel(double Num)
{
double numLevelLength;
NumLevel NLvl = new NumLevel();
if (Num > )
{
numLevelLength = MathFloor(MathLog(Num));
for (int i = NumLevelExponentLength ; i >= ; i)
{
if (numLevelLength >= NumLevelExponent[i])
{
NLvl = (NumLevel)i;
break;
}
}
}
else
{
NLvl = NumLevelYuan;
}
return NLvl;

  }

  判斷數字之間是否有跳位也就是中文中間是否要加零例如 就應該加零
 /// <summary>
/// 是否跳位
/// </summary>
/// <returns></returns>
private bool IsDumpLevel(double Num)
{
 if (Num > )
{
NumLevel? currentLevel = GetNumLevel(Num);
NumLevel? nextLevel = null;
int numExponent = thisNumLevelExponent[(int)currentLevel];

  double postfixNun = MathRound(Num % (MathPow( numExponent)));
if(postfixNun> )
nextLevel = GetNumLevel(postfixNun);
if (currentLevel != null && nextLevel != null)
{
if (currentLevel > nextLevel + )
{
return true;
}
}
}
return false;

  }

   把長數字分割為兩個較小的數字數組例如把億兆分割為億和

  因為計算機不支持過長的數字
 /// <summary>
/// 是否大於兆如果大於就把字符串分為兩部分
/// 一部分是兆以前的數字
/// 另一部分是兆以後的數字
/// </summary>
/// <param name=Num></param>
/// <returns></returns>
private bool IsBigThanTillion(string Num)
{
bool isBig = false;
if (NumIndexOf() != )
{
//如果大於兆
if (NumIndexOf() > NumLevelExponent[(int)NumLevelTrillion])
{
isBig = true;
}
}
else
{
//如果大於兆
if (NumLength > NumLevelExponent[(int)NumLevelTrillion])
{
isBig = true;
}
}
return isBig;
}

  /// <summary>
/// 把數字字符串由分開兩個
/// </summary>
/// <returns></returns>
private double[] SplitNum(string Num)
{
//兆的開始位
double[] TillionLevelNums = new double[];
int trillionLevelLength;
if (NumIndexOf() == )
trillionLevelLength = NumLength NumLevelExponent[(int)NumLevelTrillion];
else
trillionLevelLength = NumIndexOf() NumLevelExponent[(int)NumLevelTrillion];
//兆以上的數字
TillionLevelNums[] = ConvertToDouble(NumSubstring( trillionLevelLength));
//兆以下的數字
TillionLevelNums[] = ConvertToDouble(NumSubstring(trillionLevelLength ));
return TillionLevelNums;
}

   是否以壹拾開頭如果是就可以把它變為
  bool isStartOfTen = false;
while (Num >=)
{
if (Num == )
{
isStartOfTen = true;
break;
}
//Num的數位
NumLevel currentLevel = GetNumLevel(Num);

  int numExponent = thisNumLevelExponent[(int)currentLevel];
Num = ConvertToInt(MathFloor(Num / MathPow( numExponent)));
if (currentLevel == NumLevelTen && Num == )
{
isStartOfTen = true;
break;
}
}
return isStartOfTen;

   合並大於兆連個數組轉化成的貨幣字符串

  /// <summary>
/// 合並分開的數組中文貨幣字符
/// </summary>
/// <param name=tillionNums></param>
/// <returns></returns>
private string ContactNumChinese(double[] tillionNums)
{
string uptillionStr = CalculateChineseSign(tillionNums[] NumLevelTrillion true IsStartOfTen(tillionNums[]));
string downtrillionStr = CalculateChineseSign(tillionNums[] null truefalse);
string chineseCharactor = stringEmpty;
//分開後的字符是否有跳位
if (GetNumLevel(tillionNums[] * ) == NumLevelTrillion)
{
chineseCharactor = uptillionStr + NumLeverChineseSign[(int)NumLevelTrillion] + downtrillionStr;
}
else
{
chineseCharactor = uptillionStr + NumLeverChineseSign[(int)NumLevelTrillion];
if (downtrillionStr != 零元整)
{
chineseCharactor += NumChineseCharacter[] + downtrillionStr;
}
else
{
chineseCharactor += 元整;
}
}
return chineseCharactor;

  }

  遞歸計算貨幣數字的中文
 /// <summary>
/// 計算中文字符串
/// </summary>
/// <param name=Num>數字</param>
/// <param name=NL>數位級別 比如萬的 數位級別為萬</param>
/// <param name=IsExceptTen>是否以壹拾開頭</param>
/// <returns>中文大寫</returns>
public string CalculateChineseSign(double Num NumLevel? NL bool IsDumpbool IsExceptTen)
{
Num = MathRound(Num );
bool isDump = false;
//Num的數位
NumLevel? currentLevel = GetNumLevel(Num);
int numExponent = thisNumLevelExponent[(int)currentLevel];

  string Result = stringEmpty;

  //整除後的結果
int prefixNum;
//余數 當為小數的時候 分子分母各乘
double postfixNun ;
if (Num >= )
{
prefixNum = ConvertToInt(MathFloor(Num / MathPow( numExponent)));
postfixNun = MathRound(Num % (MathPow( numExponent)) );
}
else
{
prefixNum = ConvertToInt(MathFloor(Num* / MathPow( numExponent+)));
postfixNun = MathRound(Num * % (MathPow( numExponent + )) );
postfixNun *= ;
}

  if (prefixNum < )
{
//避免以壹拾開頭
if (!(NumChineseCharacter[(int)prefixNum] == NumChineseCharacter[]
&& currentLevel == NumLevelTen && IsExceptTen))
{
Result += NumChineseCharacter[(int)prefixNum];
}
else
{
IsExceptTen = false;
}
//加上單位
if (currentLevel == NumLevelYuan )
{
////當為 位不為零時 加
if (NL == null)
{
Result += NumLeverChineseSign[(int)currentLevel];
//當小數點後為零時 加
if (postfixNun == )
{
Result += EndOfInt;
}
}
}
else
{
Result += NumLeverChineseSign[(int)currentLevel];
}
 //當真正的個位為零時 加上
if (NL == null && postfixNun < && currentLevel > NumLevelYuan && postfixNun > )
{
Result += NumLeverChineseSign[(int)NumLevelYuan];

  }

  }
else
{
//當 前綴數字未被除盡時 遞歸下去
NumLevel? NextNL = null;
if ((int)currentLevel >= (int)(NumLevelTenThousand))
NextNL = currentLevel;

  Result += CalculateChineseSign((double)prefixNum NextNL isDump IsExceptTen);
if ((int)currentLevel >= (int)(NumLevelTenThousand))
{
Result += NumLeverChineseSign[(int)currentLevel];
}
}

  //是否跳位
// 判斷是否加零 比如 就要給三百 後面加零變為 三百零二
if (IsDumpLevel(Num))
{
Result += NumChineseCharacter[];
isDump = true;

  }

  //余數是否需要遞歸
if (postfixNun > )
{
Result += CalculateChineseSign(postfixNun NL isDump false);
}
else if (postfixNun == && currentLevel > NumLevelYuan )
{
//當數字是以零元結尾的加上 元整 比如一百萬元整
if (NL == null)
{
Result += NumLeverChineseSign[(int)NumLevelYuan];
Result += EndOfInt;
}
}

  return Result;
}

  外部調用的轉換方法

  /// <summary>
/// 外部調用的轉換方法
/// </summary>
/// <param name=Num></param>
/// <returns></returns>
public string ConvertToChinese(string Num)
{

  if (!IsValidated<string>(Num))
{
throw new OverflowException(數值格式不正確請輸入小於億兆的數字且最多精確的分的金額!);
}
string chineseCharactor = stringEmpty;
if (IsBigThanTillion(Num))
{
double[] tillionNums = SplitNum(Num);
chineseCharactor = ContactNumChinese(tillionNums);
}
else
{
double dNum = ConvertToDouble(Num);
chineseCharactor = CalculateChineseSign(dNum null true IsStartOfTen(dNum));
}
return chineseCharactor;
}

  小結

  個人認為程序的靈魂是算法大到一個系統中的業務邏輯小到一個貨幣數字轉中文的算法處處都體現一種邏輯思想

  是否能把需求抽象成一個好的數學模型直接關系到程序的實現的復雜度和穩定性在一些常用功能中想些不一樣的算法對我們開拓思路很有幫助


From:http://tw.wingwit.com/Article/program/net/201311/13101.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.