using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
/// <summary>
/// ConvertDoubleToChineseMoney 的摘要描述
/// </summary>
public class ConvertDoubleToChineseMoney
{
/// <summary>
/// 數位和中文大寫字元對應關係
/// </summary>
private static Dictionary<int, string> _numberChinese;
/// <summary>
/// 位數和位名(如個、拾、百等)對應關係
/// </summary>
private static Dictionary<int, string> _pointChineseNames;
/// <summary>
/// 最大位名對應的位數
/// </summary>
private const int _maxPointNameIndex = 8;
static ConvertDoubleToChineseMoney()
{
_numberChinese = new Dictionary<int, string>(10);
_numberChinese.Add(0, "零");
_numberChinese.Add(1, "壹");
_numberChinese.Add(2, "貳");
_numberChinese.Add(3, "叁");
_numberChinese.Add(4, "肆");
_numberChinese.Add(5, "伍");
_numberChinese.Add(6, "陸");
_numberChinese.Add(7, "柒");
_numberChinese.Add(8, "捌");
_numberChinese.Add(9, "玖");
_pointChineseNames = new Dictionary<int, string>(8);
_pointChineseNames.Add(_maxPointNameIndex, "億");
_pointChineseNames.Add(4, "萬");
_pointChineseNames.Add(3, "仟");
_pointChineseNames.Add(2, "佰");
_pointChineseNames.Add(1, "拾");
_pointChineseNames.Add(0, string.Empty);
_pointChineseNames.Add(-1, "角");
_pointChineseNames.Add(-2, "分");
}
/// <summary>
/// 將實數轉化為中文大寫金額
/// </summary>
/// <param name="money">用雙精度浮點數表示的金額,不能大於9.0e+15,否則拋出ArgumentException異常</param>
/// <returns>中文大寫金額字串</returns>
public static string ConvertMoney(double money)
{
if (money > 9.0e+15)
{
throw new ArgumentException("不能轉換大於9.0e+15的數");
}
if (money < 0.01)
{
return "零元";
}
//分開小數點左邊和右邊兩部分分別轉換,然後再合併
string strMoney = money.ToString();
double rightPart = 0;
if (strMoney.Contains("."))
{
rightPart = Convert.ToDouble("0."+strMoney.Split('.')[1]);
}
//double rightPart = money % 1D;
double leftPart = money - rightPart;
string strLeftPart = ConvertLeftPart(leftPart);
string strRightPart = ConvertRightPart(rightPart);
StringBuilder sbChineseMoney = new StringBuilder(strLeftPart.Length + strRightPart.Length + 2);
if (string.IsNullOrEmpty(strLeftPart))
{
strRightPart = strRightPart.TrimStart('零');
}
else
{
sbChineseMoney.Append(strLeftPart);
sbChineseMoney.Append('元');
}
sbChineseMoney.Append(strRightPart);
return sbChineseMoney.ToString();
}
/// <summary>
/// 轉換小數點左邊部分
/// </summary>
/// <param name="money"></param>
/// <returns></returns>
private static string ConvertLeftPart(double money)
{
//中文大寫金額,結果字串
StringBuilder sbChineseMoney = new StringBuilder(_maxPointNameIndex * 2);
bool isBegin = false;
//從左到右逐個將字翻譯成中文大寫金額
for (int numberIndex = _maxPointNameIndex * 2 - 1; numberIndex >= 0; numberIndex--)
{
//獲取一位元上的數字
double number = GetNumbers(money, numberIndex, numberIndex);
if (number > 0)
{
isBegin = true;
}
if (number == 0 && !isBegin)
{
continue;
}
//獲取位名的key
int pointNameIndex = GetLeftPartPointNameIndex(numberIndex);
//將當前數位元的中文字元和位元元名插入結果字串
if (number != 0)
{
//當前數位不為零,將數字和位元名直接加入結果字串尾部
sbChineseMoney.Append(_numberChinese[(int)number]);
sbChineseMoney.Append(_pointChineseNames[pointNameIndex]);
}
else
{
//當前數字為零
//如果結果字串最後一個字元不是零,才將零加入結果字串,避免多個相鄰的零出現在結果字串
if (sbChineseMoney[sbChineseMoney.Length - 1] != '零')
sbChineseMoney.Append('零');
//如果位名是個、拾、百、千,不出現在零後面
//處理位元名是萬、億的情況
if (pointNameIndex >= 4 && GetNumbers(money, numberIndex + pointNameIndex - 1, numberIndex) > 0D)
sbChineseMoney = sbChineseMoney.Insert(sbChineseMoney.Length - 1, _pointChineseNames[pointNameIndex]);
}
}
string strChineseMoney = sbChineseMoney.ToString();
strChineseMoney = strChineseMoney.TrimEnd('零');
return strChineseMoney;
}
/// <summary>
/// 處理小數點右邊部分
/// </summary>
/// <param name="money"></param>
/// <returns></returns>
private static string ConvertRightPart(double money)
{
if (money < 0.01)
{
return string.Empty;
}
money *= 100;
StringBuilder sbChineseMoney = new StringBuilder(4);
int number = (int)GetNumbers(money, 1, 1);
sbChineseMoney.Append(_numberChinese[number]);
if (number != 0)
{
sbChineseMoney.Append(_pointChineseNames[-1]);
}
number = (int)GetNumbers(money, 0, 0);
if (number != 0)
{
sbChineseMoney.Append(_numberChinese[number]);
sbChineseMoney.Append(_pointChineseNames[-2]);
}
return sbChineseMoney.ToString();
}
/// <summary>
/// 獲取指定位元數範圍的數字
/// </summary>
/// <param name="money"></param>
/// <param name="leftIndex"></param>
/// <param name="rightIndex"></param>
/// <returns></returns>
private static double GetNumbers(double money, int leftIndex, int rightIndex)
{
double pow1 = Math.Pow(10D, (double)(leftIndex + 1));
double pow2 = Math.Pow(10D, (double)rightIndex);
return (money % pow1 - money % pow2) / pow2;
}
/// <summary>
/// 獲取指定數位元索引的位元元名在_pointChineseNames上的key
/// </summary>
/// <param name="numberIndex"></param>
/// <param name="name"></param>
/// <returns>位名在_pointChineseNames上的key</returns>
private static int GetLeftPartPointNameIndex(int numberIndex)
{
int pointNameIndex = 0;
int remainder = numberIndex % 4;
if (remainder == 0)
{
if (numberIndex == 0)
{
pointNameIndex = 0;
}
else
{
for (int cast = _maxPointNameIndex; cast >= 4; cast /= 2)
{
if (numberIndex % cast == 0)
{
pointNameIndex = cast;
break;
}
}
}
}
else
{
pointNameIndex = remainder;
}
return pointNameIndex;
}
}