在通常的金融交易中,为了稳妥与慎重,常常需要把一笔阿拉伯数字书写的金额转换成汉字大写金额;
例如,把160390.50转换成大写汉字串: 壹拾陆万零叁佰玖拾元伍角整;
试把从键盘输入的阿拉伯数字金额(整数部分最多为15位,可带2位小数)转换为符合大写转换习惯的汉字大写金额;
1.说明:
注意到转换金额整数部分最多可为15位(达百万亿),如果带小数,将达到18位,为此程序采用字符串形式输入,用变量n统计字符串的长度,即输入的阿拉伯数字字符(含小数点)的个数,然后把输入的数字字符分别转换为数值;
(1)、数据结构;
字符串数组s,以字符串s输入需要转换的阿拉伯数字金额;
整型数组a,存储s转换的各位数字;
数字大写汉字字符串cs={“”,“壹”,“贰”,……,“玖”};
单位汉字字符串cd={“佰”,“拾”,“万”,“仟”,……,“元”};
(2)、金额大写转换的4个步骤;
1)、字符串s的字符转换为数字;
a[j]=s[j]-48;(j=0,1,……,n-1,小数点除外,n为s的字符个数);
2)、数字转换为大写汉字;
阿拉伯数字a[j](0~9)通过cs[a[j]]即转换为对应的大写汉字;
例如,a[j]=2时,cs[a[j]]即为对应大写汉字“贰”,即数字“2”转换为汉字“贰”;
3)、依据数字所在位置添加单位汉字;
需要转换的阿拉伯数字字符串s的整数部分(最多15位)转换为整数数组a[j](j=0,1,……,14),整数部分的个位数字为a[14],其对应单位汉字字符串中的汉字为“元”;整数部分的十位数字为a[13],对应单位汉字字符串中的汉字“拾”;……,依次类推;
当整数部分不足15位时,需要实施归位,使整数部分的个位数字归位至a[14]等;
例如,a[14]=5时,cd[14]对应单位汉字“元”,输出时在“伍”后添加单位汉字“元”,即输出“伍元”;
4)、小数部分转换;
需要转换的金额可带两位小数:小数点后第1位数字存储在变量y1中,小数点后第2位数字存储在变量y2中(若未带小数,则对应预先的赋值y1=y2=0);
若y1+y2=0:无小数部分转换与输出;
若y1+y2>0:需要视y1与y2是否为“0”分3种情形分别带“角”与“分”输出;
(3)、满足输入的特殊要求;
规范输入的转换金额为最多15位整数后可带2位小数,如果输入的是纯整数不带小数,或输入的是纯小数不带整数,程序需要满足这些特殊输入数据的转换;
为此,引入变量k,在数字字符逐位转换为数字的循环中k逐位递增,并在遇到“小数点”时把位数j赋值给t,同时k清零;
若输入的是纯整数(不带小数点),则k=n;
若输入的是纯小数(不带整数),此时t<=1且a[t-1]==0,k=1或2(此时k< n),于是把“t<=1 && a[t-1]==0”作为纯小数的标志,两位小数分别赋值给y1、y2后即输出小数转换即可;
若输入的数据有整数,其标志为“!=(t<=1 && a[t-1]==0)”,此时需要进行整数部分数字归位(t<15时)并实施转换;
(4)、转换要符合大写金额的习惯;
大写金额中该省的要省,不该省的不能省,要尽可能细致以满足通常转换习惯;
例如,在大写金额中,只要达到了相应的位数,单位汉字中的“亿”“万”与“元”是不能省略的;
同时,在转换过程中要注意处理与转换的约定习惯不相符的“多余”与“重复”的转化汉字;
例如“零仟”“零拾”等要剔除后面的“仟”“拾”字,“零万”“零元”等要剔除前面的“零”字,连续多个“零”要剔除冗余的“零”等;
为此,当满足条件“a[j]!=0 || j==2 || j==6 || (j==10 && k<4) || j==14”时才进行添加单位汉字,前者避免出现“零仟”等,后4个条件为对应的“万”“亿”“万”与“元”不能省;
同时,当满足条件“a[j]==0 && a[j+1]>0 && j!=14”,才输出汉字“零”,前2个条件避免出现重复“零”,后1个条件避免出现多余的“零”;
转换最后为“元”或“角”时,通常加上“整”(或“正”),以表示转换结束;而转换最后若分“分”时,不必加“整”字;
(5)、为了确保转换准确,限制输入的字符(含小数点)个数n不得超出18个,整数部分的位数k不得超过15,为慎重,当n>18或k>15时程序不予转换而退出;
2.程序设计:
#include<stdio.h>
#include<string.h>
int main()
{
char s[20];
int y1,y2,k,n,j,t,a[20];
char* cs[]={"","壹","贰","叁","肆","伍","陆","柒","捌","玖"};
char* cd[]={"佰","拾","万","仟","佰","拾","亿","仟","佰","拾","万","仟","佰","拾","元"};
printf("请输入金额(整数部分最多15位):");
scanf("%s",s);
n=strlen(s);
y1=y2=0;
t=n;
if(n>18)
{
printf("输入的数超过范围,请重新输入\n");
return;
}
for(k=0,j=0;j<=n-1;j++)
{
if(s[j]>=48 && s[j]<=57) /*把输入的数字字符转换为数值*/
{
k++;
if(k>15)
{
printf("输入的数超过范围,请重新输入\n");
return;
}
a[j]=s[j]-48;
}
else
{
t=j;
k=0; /*遇上小数点时t=j,k=0*/
}
}
if(k==1 && k<n)
y1=a[t+1];
if(k==2 && k<n) /*记录金额的小数部分*/
{
y1=a[t+1];
y2=a[t+1];
}
if(!(t<=1 && a[t-1]==0)) /*有整数则转换并输出整数部分*/
{
if(t<15) /*整数部分数字归位*/
for(j=14;j>=15-t;j--)
a[j]=a[j-15+t];
for(j=15-t;j<=14;j++)
{
printf("%s",cs[a[j]]); /*输出阿拉伯数字转换的汉字*/
if(a[j]==0)
k++;
else
k=0; /*统计连续0的个数*/
if(a[j]!=0 || j==2 || j==6 || (j==10 && k<4) || j==14)
printf("%s",cs[j]); /*输出对应的单位汉字*/
if(a[j]==0 && a[j+1]>0 && j!=14)
printf("零");
}
if(y1+y2==0)
printf("整\n");
}
if(y1+y2>0) /*有小数则输出小数转换部分*/
{
if(y1==0 && y2>0)
printf("零%s分\n",cs[y2]);
if(y1>0)
{
if(a[14]==0)
printf("零");
if(y2==0)
printf("%s角整\n",cs[y1]);
else
printf("%s角%s分\n",cs[y1],cs[y2]);
}
}
}
3.程序运行示例及其注意事项:
请输入金额(整数部分最多15位):570120003040005.6
伍柒壹贰零壹叁贰肆陆零叁捌零肆佰零伍佰陆角整
请输入金额(整数部分最多15位):120712071207120.7
壹贰壹贰零柒叁壹肆贰伍陆零柒柒壹捌贰玖佰零柒拾壹万贰仟佰零柒角整
注意:金额大写转换程序设计不太复杂,但要确保适应各种常见的输入,尤其在细节上要符合通常转换习惯,并非轻而易举;
对于输入纯整数或纯小数金额的转换,请读者自己运行程序练习;
变通:随着经济发展,若干年后将达到甚至超过千万亿级台阶,请修改程序,提升转换金额达亿亿级,即转换金额的整数部分增加到17位;