C#基于纯数学方法递归实现货币数字转换中文功能详解
本文实例讲述了C#基于纯数学方法递归实现货币数字转换中文功能。分享给大家供大家参考,具体如下:
最近由于项目的原因,需要写一个货币数字转换中文的算法,先在网了找了一下,结果发现无一列外都是用(Replace)替换的方式来实现的,所以想写个另外的算法;因为本人是学数学出身的,所以用纯数学的方法实现。
注意:本文中的算法支持小于1023(也就是9999亿兆)货币数字转化。
货币中文说明:在说明代码之前,首先让我们回顾一下货币的读法。
10020002.23 读为壹仟零贰万零贰元贰角叁分
1020 读为壹仟零贰拾元整。
100000 读为拾万元整
0.13 读为壹角叁分
代码:
测试工程
staticvoidMain(string[]args)
{
Console.WriteLine("请输入金额");
stringinputNum=Console.ReadLine();
while(inputNum!="exit")
{
//货币数字转化类
NumCastnc=newNumCast();
if(nc.IsValidated<string>(inputNum))
{
try
{
stringchineseCharacter=nc.ConvertToChinese(inputNum);
Console.WriteLine(chineseCharacter);
}
catch(Exceptioner)
{
Console.WriteLine(er.Message);
}
}
else
{
Console.WriteLine("不合法的数字或格式");
}
Console.WriteLine("\n请输入金额");
inputNum=Console.ReadLine();
}
Console.ReadLine();
}
货币转化类(NumCast类)功能介绍
1.常量的规定
///<summary>
///数位
///</summary>
publicenumNumLevel{Cent,Chiao,Yuan,Ten,Hundred,Thousand,TenThousand,hundredMillon,Trillion};
///<summary>
///数位的指数
///</summary>
privateint[]NumLevelExponent=newint[]{-2,-1,0,1,2,3,4,8,12};
///<summary>
///数位的中文字符
///</summary>
privatestring[]NumLeverChineseSign=newstring[]{"分","角","元","拾","佰","仟","万","亿","兆"};
///<summary>
///大写字符
///</summary>
privatestring[]NumChineseCharacter=newstring[]{"零","壹","贰","叁","肆","伍","陆","柒","捌","玖"};
///<summary>
///整(当没有角分时)
///</summary>
privateconststringEndOfInt="整";
2.数字合法性验证,采用正则表达式验证
///<summary>
///正则表达验证数字是否合法
///</summary>
///<paramname="Num"></param>
///<returns></returns>
publicboolIsValidated<T>(TNum)
{
Regexreg=newRegex(@"^(([0])|([1-9]\d{0,23}))(\.\d{1,2})?$");
if(reg.IsMatch(Num.ToString()))
{
returntrue;
}
returnfalse;
}
3.获取数位例如1000的数位为NumLevel.Thousand
///<summary>
///获取数字的数位使用log
///</summary>
///<paramname="Num"></param>
///<returns></returns>
privateNumLevelGetNumLevel(doubleNum)
{
doublenumLevelLength;
NumLevelNLvl=newNumLevel();
if(Num>0)
{
numLevelLength=Math.Floor(Math.Log10(Num));
for(inti=NumLevelExponent.Length-1;i>=0;i--)
{
if(numLevelLength>=NumLevelExponent[i])
{
NLvl=(NumLevel)i;
break;
}
}
}
else
{
NLvl=NumLevel.Yuan;
}
returnNLvl;
}
4.判断数字之间是否有跳位,也就是中文中间是否要加零,例如1020就应该加零。
///<summary>
///是否跳位
///</summary>
///<returns></returns>
privateboolIsDumpLevel(doubleNum)
{
if(Num>0)
{
NumLevel?currentLevel=GetNumLevel(Num);
NumLevel?nextLevel=null;
intnumExponent=this.NumLevelExponent[(int)currentLevel];
doublepostfixNun=Math.Round(Num%(Math.Pow(10,numExponent)),2);
if(postfixNun>0)
nextLevel=GetNumLevel(postfixNun);
if(currentLevel!=null&&nextLevel!=null)
{
if(currentLevel>nextLevel+1)
{
returntrue;
}
}
}
returnfalse;
}
5.把长数字分割为两个较小的数字数组,例如把9999亿兆,分割为9999亿和0兆,因为计算机不支持过长的数字。
///<summary>
///是否大于兆,如果大于就把字符串分为两部分,
///一部分是兆以前的数字
///另一部分是兆以后的数字
///</summary>
///<paramname="Num"></param>
///<returns></returns>
privateboolIsBigThanTillion(stringNum)
{
boolisBig=false;
if(Num.IndexOf('.')!=-1)
{
//如果大于兆
if(Num.IndexOf('.')>NumLevelExponent[(int)NumLevel.Trillion])
{
isBig=true;
}
}
else
{
//如果大于兆
if(Num.Length>NumLevelExponent[(int)NumLevel.Trillion])
{
isBig=true;
}
}
returnisBig;
}
///<summary>
///把数字字符串由‘兆'分开两个
///</summary>
///<returns></returns>
privatedouble[]SplitNum(stringNum)
{
//兆的开始位
double[]TillionLevelNums=newdouble[2];
inttrillionLevelLength;
if(Num.IndexOf('.')==-1)
trillionLevelLength=Num.Length-NumLevelExponent[(int)NumLevel.Trillion];
else
trillionLevelLength=Num.IndexOf('.')-NumLevelExponent[(int)NumLevel.Trillion];
//兆以上的数字
TillionLevelNums[0]=Convert.ToDouble(Num.Substring(0,trillionLevelLength));
//兆以下的数字
TillionLevelNums[1]=Convert.ToDouble(Num.Substring(trillionLevelLength));
returnTillionLevelNums;
}
6.是否以“壹拾”开头,如果是就可以把它变为“拾”
boolisStartOfTen=false;
while(Num>=10)
{
if(Num==10)
{
isStartOfTen=true;
break;
}
//Num的数位
NumLevelcurrentLevel=GetNumLevel(Num);
intnumExponent=this.NumLevelExponent[(int)currentLevel];
Num=Convert.ToInt32(Math.Floor(Num/Math.Pow(10,numExponent)));
if(currentLevel==NumLevel.Ten&&Num==1)
{
isStartOfTen=true;
break;
}
}
returnisStartOfTen;
7.合并大于兆连个数组转化成的货币字符串
///<summary>
///合并分开的数组中文货币字符
///</summary>
///<paramname="tillionNums"></param>
///<returns></returns>
privatestringContactNumChinese(double[]tillionNums)
{
stringuptillionStr=CalculateChineseSign(tillionNums[0],NumLevel.Trillion,true,IsStartOfTen(tillionNums[0]));
stringdowntrillionStr=CalculateChineseSign(tillionNums[1],null,true,false);
stringchineseCharactor=string.Empty;
//分开后的字符是否有跳位
if(GetNumLevel(tillionNums[1]*10)==NumLevel.Trillion)
{
chineseCharactor=uptillionStr+NumLeverChineseSign[(int)NumLevel.Trillion]+downtrillionStr;
}
else
{
chineseCharactor=uptillionStr+NumLeverChineseSign[(int)NumLevel.Trillion];
if(downtrillionStr!="零元整")
{
chineseCharactor+=NumChineseCharacter[0]+downtrillionStr;
}
else
{
chineseCharactor+="元整";
}
}
returnchineseCharactor;
}
8.递归计算货币数字的中文
///<summary>
///计算中文字符串
///</summary>
///<paramname="Num">数字</param>
///<paramname="NL">数位级别比如1000万的数位级别为万</param>
///<paramname="IsExceptTen">是否以‘壹拾'开头</param>
///<returns>中文大写</returns>
publicstringCalculateChineseSign(doubleNum,NumLevel?NL,boolIsDump,boolIsExceptTen)
{
Num=Math.Round(Num,2);
boolisDump=false;
//Num的数位
NumLevel?currentLevel=GetNumLevel(Num);
intnumExponent=this.NumLevelExponent[(int)currentLevel];
stringResult=string.Empty;
//整除后的结果
intprefixNum;
//余数当为小数的时候分子分母各乘100
doublepostfixNun;
if(Num>=1)
{
prefixNum=Convert.ToInt32(Math.Floor(Num/Math.Pow(10,numExponent)));
postfixNun=Math.Round(Num%(Math.Pow(10,numExponent)),2);
}
else
{
prefixNum=Convert.ToInt32(Math.Floor(Num*100/Math.Pow(10,numExponent+2)));
postfixNun=Math.Round(Num*100%(Math.Pow(10,numExponent+2)),2);
postfixNun*=0.01;
}
if(prefixNum<10)
{
//避免以‘壹拾'开头
if(!(NumChineseCharacter[(int)prefixNum]==NumChineseCharacter[1]
&¤tLevel==NumLevel.Ten&&IsExceptTen))
{
Result+=NumChineseCharacter[(int)prefixNum];
}
else
{
IsExceptTen=false;
}
//加上单位
if(currentLevel==NumLevel.Yuan)
{
////当为“元”位不为零时加“元”。
if(NL==null)
{
Result+=NumLeverChineseSign[(int)currentLevel];
//当小数点后为零时加"整"
if(postfixNun==0)
{
Result+=EndOfInt;
}
}
}
else
{
Result+=NumLeverChineseSign[(int)currentLevel];
}
//当真正的个位为零时加上“元”
if(NL==null&&postfixNun<1&¤tLevel>NumLevel.Yuan&&postfixNun>0)
{
Result+=NumLeverChineseSign[(int)NumLevel.Yuan];
}
}
else
{
//当前缀数字未被除尽时,递归下去
NumLevel?NextNL=null;
if((int)currentLevel>=(int)(NumLevel.TenThousand))
NextNL=currentLevel;
Result+=CalculateChineseSign((double)prefixNum,NextNL,isDump,IsExceptTen);
if((int)currentLevel>=(int)(NumLevel.TenThousand))
{
Result+=NumLeverChineseSign[(int)currentLevel];
}
}
//是否跳位
//判断是否加零,比如302就要给三百后面加零,变为三百零二。
if(IsDumpLevel(Num))
{
Result+=NumChineseCharacter[0];
isDump=true;
}
//余数是否需要递归
if(postfixNun>0)
{
Result+=CalculateChineseSign(postfixNun,NL,isDump,false);
}
elseif(postfixNun==0&¤tLevel>NumLevel.Yuan)
{
//当数字是以零元结尾的加上元整比如1000000一百万元整
if(NL==null)
{
Result+=NumLeverChineseSign[(int)NumLevel.Yuan];
Result+=EndOfInt;
}
}
returnResult;
}
9.外部调用的转换方法。
///<summary>
///外部调用的转换方法
///</summary>
///<paramname="Num"></param>
///<returns></returns>
publicstringConvertToChinese(stringNum)
{
if(!IsValidated<string>(Num))
{
thrownewOverflowException("数值格式不正确,请输入小于9999亿兆的数字且最多精确的分的金额!");
}
stringchineseCharactor=string.Empty;
if(IsBigThanTillion(Num))
{
double[]tillionNums=SplitNum(Num);
chineseCharactor=ContactNumChinese(tillionNums);
}
else
{
doubledNum=Convert.ToDouble(Num);
chineseCharactor=CalculateChineseSign(dNum,null,true,IsStartOfTen(dNum));
}
returnchineseCharactor;
}
小结:
个人认为程序的灵魂是算法,大到一个系统中的业务逻辑,小到一个货币数字转中文的算法,处处都体现一种逻辑思想。
是否能把需求抽象成一个好的数学模型,直接关系到程序的实现的复杂度和稳定性。在一些常用功能中想些不一样的算法,对我们开拓思路很有帮助。
更多关于C#相关内容感兴趣的读者可查看本站专题:《C#数学运算技巧总结》、《C#窗体操作技巧汇总》、《C#常见控件用法教程》、《WinForm控件用法总结》、《C#程序设计之线程使用技巧总结》、《C#数据结构与算法教程》、《C#数组操作技巧总结》及《C#面向对象程序设计入门教程》
希望本文所述对大家C#程序设计有所帮助。