任意数字金额转化大写(c++,vs2017实现),精确到分,只要空间足够数字大小无上限。

本文介绍了一种将大数值转换为汉字金额表示的算法,详细解释了如何处理各种特殊情况,如连续零、小数点后的零等,并通过代码示例展示了实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思路在这里插入图片描述

我们以万为为单位进行分割成段,思路就是每每个段间的数都几千几百几十的,例如图第一个段内为10,我们就可以说是10-万亿,第二段为1234段内为一千两百三十四,加上段间的单位亿后就是其实际大小,如此做法我们拼接所有段就能实现。

2.难点

(1)段间单位的演算

单位的演变,当数越长时,其段间的单位就是有万与亿的组合且万一定在亿的前面,怎么算呢?段间的单位为段数有关系,我们假设段数为gapCount = 4,段间单位的大小为gapCount/2 = 2,所以是有两个字组成的,gapCount%2 = 0,所以第一个位置为万,其余的单位位置为亿,如果gapCount%2 = 1,则单位上所有的空为亿字,如此可知第四段后的单位为万亿·,符合图片。

(2)有关于各种情况零的处理

此算法中进行了大量有关于零的异常处理,比较多,典型的就是数字中间的0的处理(连续的零和段内千位上的零转化),与零的转化,还有小数零的转化等等情况。

运行结果

给大家看看一个宝贝,我的支票金额(斜眼笑),虽然大数的转化意义不大,但是把马云的钱换为津巴布韦币说不定能用上,开个玩笑。在这里插入图片描述


	#include<iostream>
	using namespace std;
	#define NUM_LENGTH 100//数组大小
	//全局变量
	int bigNumBeg = 0;//整数的起始下标
	int bigNumEnd = 0;//整数的结束下标
	bool numFlag = false;//是否存在小数
	int smallNumBeg = 0;//小数的起始下标
	int wNumBeg = 0;//输出的宽字符数组已使用的位置
	bool zeroFlag = false;//判断数字间是否存在连续的零
	bool smallInteg = false;//判断小数是否要加整字
	bool onlyBig = false;//判断是否只存在整数部分
	bool allSmallZero = true;//判断小数部分是否全为零
	bool allBigZero = true;//判断整数部分是否全为零
	//宽字符数据
	struct WNumData
	{
		wchar_t *wNum;//宽字符指针,指向数组
		wchar_t *carry;//段内宽数量级指针,指向数组
		wchar_t *gapCarry;//段间宽数量级指针,指向数组
		wchar_t *unit;//段间单位指针,指向数组
		wchar_t *integer;//指向“整字”的指针
	};
	/** 数字选择与转化
	* num为字符数组的字符元素
	* wNum存储转化后的看宽字符数组
	* wData宽字符数据
	*/
	void NumSelect(char num, wchar_t& wNum, WNumData& wData)
	{
		switch (num)//char型数字字符转化为汉字大写数字
		{
		case '0':
			if (zeroFlag)//段内的第一个零一定可以
			{
				wNum = wData.wNum[0];
				zeroFlag = false;//零的紧接着零不用重复写
			}
			else//后续的零为空格
			{
				wNum = ' ';
			}
			break;
		case '1':
			wNum = wData.wNum[1];
			zeroFlag = true;//后续可为零
			break;
		case '2':
			wNum = wData.wNum[2];
			zeroFlag = true;//后续可为零
			break;
		case '3':
			wNum = wData.wNum[3];
			zeroFlag = true;//后续可为零
			break;
		case '4':
			wNum = wData.wNum[4];
			zeroFlag = true;//后续可为零
			break;
		case '5':
			wNum = wData.wNum[5];
			zeroFlag = true;//后续可为零
			break;
		case '6':
			wNum = wData.wNum[6];
			zeroFlag = true;//后续可为零
			break;
		case '7':
			wNum = wData.wNum[7];
			zeroFlag = true;//后续可为零
			break;
		case '8':
			wNum = wData.wNum[8];
			zeroFlag = true;//后续可为零
			break;
		case '9':
			wNum = wData.wNum[9];
			zeroFlag = true;//后续可为零
			break;
		}
	}
	/** 数量级选择
	* len段内数字个数
	* wCarry段内数字数量级选择
	* wData宽字符数据
	*/
	void carrySelect(int len, char num, wchar_t& wCarry, WNumData& wData)
	{
		if (len >= 2 && num != '0')
		{
			wCarry = wData.carry[len - 2];
		}
		else
		{
			wCarry = ' ';
		}
	}
	/** 段间的进制选择
	* gapCount为数字以万为单位所分的段数
	* wUnit为段段间的数字后面的单位选择
	* wData宽字符数据
	*/
	void unitSelect(int& gapCount, wchar_t* wUnit, WNumData& wData)
	{
		int gapbigNumBeg = gapCount % 2;//这里的gap不取零从1开始,为了更有序的遍历
		int iterCount = gapCount / 2;
		if (gapbigNumBeg == 1 && iterCount == 0)//gapCount为1时元为单位,就是万以内的数
		{
			wUnit[wNumBeg] = wData.unit[0];//赋值圆
			wNumBeg++;
		}
		else//数字大于万时gapCount > 1
		{
			for (int i = 0; i < iterCount; i++)//进行段间的单位设置,例如“亿亿”,“万亿等”
			{
				if (gapbigNumBeg == 0)
				{
					wUnit[wNumBeg] = wData.gapCarry[gapbigNumBeg];
					wNumBeg++;
					gapbigNumBeg = 1;
				}
				else
				{
					wUnit[wNumBeg] = wData.gapCarry[gapbigNumBeg];
					wNumBeg++;
				}
			}
		}
	}
	
	/** 尾零的排查
	* out为输出的宽字符数组
	*/
	void rearCheckZero(wchar_t *out)
	{
		int outLength = wNumBeg - 1;
		for (int i = outLength; i > 1; i--)
		{
			if (out[i] != ' ')
			{
				if (out[i] == (wchar_t)L'零')
				{
					out[i] = ' ';
				}
				break;
			}
		}
	}
	/** 中零的排查
	* begin为查找开始的位置
	* len为查找的长度
	* bigNum 所被查找的数组
	* return 段内中是否全为零
	*/
	bool midCheckZero(int begin, int len, char *bigNum)
	{
		bool midZeroFlag = true;
		for (int i = 0; i < len; i++)
		{
			if (bigNum[begin] != '0')
			{
				midZeroFlag = false;
				bigNumBeg = bigNumBeg;
				return midZeroFlag;
			}
			begin++;
		}
		bigNumBeg = bigNumBeg + 4;
		return midZeroFlag;
	}
	/** 检查小数部分是否为全零。
	* beg为查找开始的位置
	* precise 小数部分的精度
	* smallNum 被查找的数组
	*/
	void smallZeroCheck(int beg, int precise, char * smallNum)
	{
		for (int i = 0; i < precise; i++)
		{
			if (smallNum[beg] != '0')
			{
				allSmallZero = false;
				
			}
			beg++;
		}
	}
	/**检查整数是否全为零
	* num指向字符数组的指针
	*/
	void bigZeroCheck(char *num)
	{
		for (int i = bigNumBeg; i < bigNumEnd; i++)
		{
			if (num[i] != '0')
			{
				allBigZero = false;
				return;
			}
		}
	}
	
	/** 输入的字符数组检查
	*num 为数字数组指针
	* return 字符数组格式是否异常
	*/
	bool inNumCheck(char *num)
	{
		int length = strlen(num);
		bool numCheckFlag = true;
		int dotCheck = 0;
		if (num[0] == '.')
		{
			numCheckFlag = false;
			return numCheckFlag;
		}
		for (int i = 0; i < length; i++)
		{
			if (num[i] == '.')//查到第一个小数点,如果有第二个或者多个则数据格式有误
			{
				dotCheck++;
				if (dotCheck > 1)
				{
					numCheckFlag = false;
					return numCheckFlag;
				}
			}
			if ((num[i] >= '0'&& num[i] <= '9') || num[i] == '.')
			{ }
			else
			{
				numCheckFlag = false;
				return numCheckFlag;
			}
		}
		return numCheckFlag;
	}
	/** 段内的字符数组向宽数组转化
	* begin转化开始位置
	* bigNum转化数组的指针
	* out转化后接受宽字符的数组指针
	* gapCount 分段个数
	*/
	void gapIn(int begin ,int len, char *bigNum, wchar_t *out, WNumData& wData , int& gapCount)
	{
		//滑动窗口
		int i = 0;//窗口起始点
		int j = len;//窗口长度
		while (i != len)
		{
			NumSelect(bigNum[begin], out[wNumBeg], wData);
			wNumBeg++;//写入一个数字,移位置
			carrySelect(j, bigNum[begin], out[wNumBeg], wData);
			j--;
			wNumBeg++;//段内写入一个单位,移动位置
			i++;
			begin++;
		}
		rearCheckZero(out);
		unitSelect(gapCount, out, wData);
		bigNumBeg = bigNumBeg + i;//记录已经转变的下一个下标
	}
	
	
	/**整数转换
	* bigNum转化数组的指针
	* out转化后接受宽字符的数组指针
	* wData宽字符数据
	*/
	void TransBig(char *bigNum, wchar_t *out, WNumData& wData)
	{
		bigZeroCheck(bigNum);//整数零的检查
		if (allBigZero)//如果全零则退出函数
		{
			return;
		}
		int bigNumLen = bigNumEnd - bigNumBeg;//元素个数
		int lenMax = bigNumLen % 4 ;//数字对万取余的后长度,为与最高的数量级位
		int gapCount = bigNumLen / 4 + 1;//以万为单位分的段数
		bool subFlag = false;//判断getCount是否被lenMax情况减过一次,如果剪过一次则其他情况不减。
		while (bigNumBeg != bigNumEnd )//遍历整数部分
		{
			if (lenMax != 0)//有两种可能,万以内的数字或者剩余的最高位数字
			{
				
				gapIn(0, lenMax, bigNum, out, wData, gapCount);
				gapCount--;
				subFlag = true;
				lenMax = 0;//置为零,lenMax只会执行一次
				if (gapCount == 0)//万以内的数字,在末尾加整字
				{
					out[wNumBeg] = wData.integer[0];//添加整字
					wNumBeg++;//移动位置
				}
				continue;
			}
			else//能万整除的部分,也就是划分的满四个的片段
			{
				if (!subFlag)
				{
					gapCount--;
				}
				for (gapCount; gapCount >=1; gapCount--)
				{
					if (midCheckZero(bigNumBeg,4,bigNum))//此段内是否全为零,全为零则退出此循环
					{
						continue;
					}
					zeroFlag = true;//重置标记,允许各个段‘千位’零的存在
					gapIn(bigNumBeg, 4, bigNum, out, wData, gapCount);//当gap=1时选择元为单位
					
				}
				out[wNumBeg] = wData.integer[0];//添加整字
				wNumBeg++;
			}
		}
	}
	/** 小数部分的转换
	* smallNum转化数组的指针
	* out转化后接受宽字符的数组指针
	* wData宽字符数据
	*/
	void TransSmall(char* smallNum, wchar_t *out, WNumData& wData)
	{
		int precise = 2;//精度为2,也就是精确到分
		int indexTemp = smallNumBeg;//临时存储下标。
		//判断是否全为零
		smallZeroCheck(smallNumBeg, precise, smallNum);
		if (allSmallZero)
		{
			return;
		}
		int jIndexTemp = wNumBeg;//临时存储下标
		while (!onlyBig)//当不只存在整数部分,删除整数部分多余的整字
		{
			if (out[jIndexTemp] == L'整')
			{
				out[jIndexTemp] = ' ';//替换为空格
				break;
			}
			jIndexTemp--;
		}
		for (int i = 0; i < precise; i++)
		{
			zeroFlag = true;//单位角上的零可被转化
			NumSelect(smallNum[smallNumBeg], out[wNumBeg], wData);
			smallNumBeg++;//读取一个字符,移动
			wNumBeg++;//写入一个数字,移位置
			out[wNumBeg] = wData.unit[i + 1];//写入一个单位,移位置
			wNumBeg++;
	
			if (i == 0 && smallNum[indexTemp] != '0' && (smallNum[indexTemp + 1] == '0' 
				|| smallNum[indexTemp + 1] == '\0'))//角位不为零分位为零,则加整终止。
			{
				out[wNumBeg] = wData.integer[0];
				wNumBeg++;
				break;
			}
		}
	}
	/** 数字转变
	* num转化数组的指针
	* out转化后接受宽字符的数组指针
	* wData宽字符数据
	*/
	void TransNum(char *num, wchar_t* out, WNumData& wData )
	{
		int numLen = 0;//字符数组的长度
		while (num[numLen] != '\0')//记录整数部分开始与结束的下标,记录小数部分开始的下标
		{
			if (num[numLen] == '.' && num[numLen + 1] != '\0')//存在小数点且小数点后不为'\0'
			{
				numFlag = true;
				bigNumEnd = numLen;
				numLen++;
				smallNumBeg = numLen;
				break;
			}
			numLen++;
		}
		if (!numFlag)//不存在小数部分
		{
			onlyBig = true;
			bigNumEnd = numLen;
			TransBig(num, out, wData);
		}
		else //存在小数部分,有两种可能,一是只存在小数部分,二是既存在小数部分又存在整数部分
		{
			if (smallNumBeg == 2 && num[smallNumBeg - 2] == '0')//仅有小数部分
			{
				onlyBig = true;
				TransSmall(num, out, wData);
			}
			else//即存在不为零的整数部分又存在小数部分
			{
				onlyBig = false;
				TransBig(num, out, wData);
				TransSmall(num, out, wData);
			}
		}
		//判断整数部分与小数部分是否全为零如果是则输出零圆整
		if (allBigZero && allSmallZero)
		{
			cout << "零圆整";
			return;
		}
	}
	//打印输出
	void printOut(wchar_t *out)
	{
		int i = 0;
		wcout.imbue(locale("", LC_CTYPE));
		while (out[i] != '\0')
		{
			if (out[i] != ' ')
			{
				wcout << out[i];
			}
			i++;
		}
		cout << endl;
	}
	int main()
	{
		char num[NUM_LENGTH/2];//输入的字符数组
		cout << "请输入要转换的数字:";
		while (cin >> num)//数字输入
		{
			if (cin.get() == '\n')
			{
				break;
			}
		}
		if (!inNumCheck(num))//数字规格检查
		{
			cout << "数字输入不符合规格,请重新输入" << endl;
			system("pause");
			return 0;
		}
		wchar_t out[NUM_LENGTH] = { 0 };//输出的宽字符数组
		WNumData wData;
		wData.wNum = (wchar_t*)L"零壹贰叄肆伍陆柒捌玖";
		wData.carry = (wchar_t*)L"拾佰仟";//段内进制
		wData.gapCarry = (wchar_t*)L"万亿";//段间进制
		wData.unit = (wchar_t*)L"圆角分";
		wData.integer = (wchar_t*)L"整";
		TransNum(num, out, wData);//转化
		printOut(out);//打印输出
		system("pause");
		return 0;
	}

总结

本人是萌新,如果代码有冗余或者有bug请见谅,可在评论区提出来,我会多多学习的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值