天天看点

阿拉伯数字转换成中文读法的C语言程序

记一道评论区的题目

​ 导语 : 作为一个西电的菜鸡 , 每天只能和不超过两天的ddl较劲 , 啥也不懂 , 啥也不会. 因为家里硬盘不太够了所以把作业的代码传到博客里保存. 可以预见到的 , 遭到了真正大佬的嘲笑. 其中 , 二哥在讨论区里留下一道题目 , 我觉得还挺有意思的. 所以试着实现了一下 , 作为博客的第二篇拙作.

1.题目

阿拉伯数字转换成中文读法的C语言程序

​ 分析一下 , 是想实现一个小写数字到中文大写数字的转化. 那么 , 如果我们想要实现这个功能 , 首先我们要重新回顾一下中文数字的读法和英文读法的区别.

2.回顾背后的数学知识

​ 我们在小学二年级的时候就学过数字的读法 , 在初中的时候基本上了解到了英文的数字的读法.

比如对于31980 , 中文读作"三万一千九百八十" , 英文读作"tirty-one thousand and nine hundred eighty". 那么中文和英文对于数字的读法来说有什么不同呢?

​ 首先 , 我们要了解一下中文和英文当中对于数字的单位. 在中文中 , 有个 , 十 , 百 , 千 , 万 , 十万 , 百万 , 千万 , 亿 , 十亿… 在英文中 , 有1-20的不同的读法 , x0的读法 , hundred , thousand , million , billion… 通过比较我们不难发现其规律. 中文的数字单位是以四个为一循环 , 比如四位引出一个万 , 再四位引出一个亿. 而英语中是以三位为一个计数段 , 引出一个定义的单位.

1 , 000 , 000 , 000 1,000,000,000 1,000,000,000

英语国家的人看数字的方式.

10 , 0000 , 0000 10,0000,0000 10,0000,0000

中国人看数字的方式.

​ 两者相似的 , 对于比较小的位数划分的比较详细一些 , 而对于比较大的位数 , 中国人采取与小位数的单位相结合同时适度引入新单位来记录数字 , 而英语采用每三位定义一个单位的方式记录数字.

​ 对于中文来说 , 比较特殊的一点是 , 如果在数的中间有0的话习惯中间读一个"零"表示区分层次.

如 : 1023读作"一千零二十三" , 但是如果从某一位开始之后全是0的情况下则不读这个0. 而这个"零"的读法便是这个小demo最有意思的地方.

3.程序设计和算法思路

​ 通过上面对问题的回顾 , 我们大致可以想到一个思路. 将一个数字按4位为一组分隔开. 将0-9999的数实现向中文的转换 , 然后在后面加上单位即可. 比如12345 , 可以看作1,2345 , 那么第一组2345就读作"二千三百四十五" , 这里为了叙述方便 , 将中文大写数字"壹"写作了中文小写数字"一". 这一组因为最低位是个位 , 所以单位为空. 而第二组只有一个1 , 读作"一" , 它处于万位上. 所以后面加上单位"万". 所以读作"一万二千三百四十五".

​ 下面主要讨论如何将0-9999内的数字实现. 很自然的 , 我们想到模拟人来读数字的方法. 首先,我们将所读数的千位 , 百位 , 十位 , 个位存在一个整型数组里.

下 面 列 出 需 要 讨 论 的 几 种 情 况 : 1234 1 , 2 , 3 , 4 1 0 , 0 , 0 , 1 1001 1 , 0 , 0 , 1 1000 1 , 0 , 0 , 0 1110 1 , 1 , 1 , 0 0 0 , 0 , 0 , 0 下面列出需要讨论的几种情况:\\ 1234\\ 1,2,3,4\\ 1\\ 0,0,0,1\\ 1001\\ 1,0,0,1\\ 1000\\ 1,0,0,0\\ 1110\\ 1,1,1,0\\ 0\\ 0,0,0,0 下面列出需要讨论的几种情况:12341,2,3,410,0,0,110011,0,0,110001,0,0,011101,1,1,000,0,0,0

​ 首先来看第一种. 第一种读作"一千二百三十四" , 可以看到 , 我们开始读是从第0位开始读的 , 而且每一位都读到了. 这里我们可以得出对应规则 : 第0位对应单位为"千",如果不为0应将其读了数字名后加"千" , 之后类推.

​ 再看第二种 , 显然之前的三位都没有读到 , 是从第四位开始读的. 这里我们可以体会到 : 应该设置一个变量 , 我们设置为start. 我们通过start的状态确定读数的开始和停止.

​ 第三种读作"一千零一". 这里我们引出了中间读"零"的问题. 我们看到中间虽然有两个0 , 但是只读一次. 我们可以认为只读第一次出现的0. 所以这里我们引出变量firstzero , 用来确定是否为第一个0 , 只有第一个0会读.

​ 第四种读作"一千". 这里我们可以发现一个概念. 若从某位数开始全是0 , 则这个第一个0不读. 所以引入alwayszero变量 , 用来确定是否之后全是0 , 若是则不读 , 不是则读第一个0.

​ 第五种读作"一千一百一十". 如果我们带入前四条对应的规则应读作"一千一百一十零". 这是因为最后一位0也是第一个0且满足到最后全是0 , 所以会读出来. 那么我们如何解决呢? 这里我们对第三条规则做一个补充 : 只有第一个0 ,不在最后一位(个位)上 , 且之后不全为0时才读零.

​ 第六种 , 对于0来说 , 由于start是遇到非0元素才开始读 , 所以0是不会开启读数的. 因此 , 我们需要一个特别判定 : 当输入数字为0时只输入0 , 当数字非0时才按照前五条规则开始读数.

​ 了解原理之后 , 废话不多说 , 上代码.(注 : 这里代码中的print函数是预先定义的读数字的函数 , 比如print(1) , 输出一)

//输出0-9999的中文读法
void thousandmaxprint(int n) {
	//分离位数
    int bit[4] = { 0,0,0,0 };
	bit[0] = n / 1000;
	bit[1] = n % 1000 / 100;
	bit[2] = n % 100 / 10;
	bit[3] = n % 10;
	
    int start = 0;
	//开始状态变量,当其为1时才会开始打印
	int firstzero = 1;
	//寻找中间的第一个0,输出后会置为0
	int alwayszero = 1;
	//是否从第一个0开始全部是0

	//如果是0
	if (n == 0)
		print(n);
	else {			//如果不是0
		//开始遍历
		for (int tempcount = 0; tempcount < 4; tempcount++) {
			if (bit[tempcount] != 0 || tempcount == 3)
				//寻找到最后一位或已经遍历到最后一位
				start = 1;
			if (start) {
				if (bit[tempcount] != 0) {
					if (tempcount == 0) {
						print(bit[tempcount]);
						printf("千");
					}
					if (tempcount == 1) {
						print(bit[tempcount]);
						printf("百");
					}
					if (tempcount == 2) {
						print(bit[tempcount]);
						printf("十");
					}
					if (tempcount == 3) {
						print(bit[tempcount]);
					}
				}
				else {
					if (firstzero && tempcount < 3) {
						//如果是第一个0且不是最末位,则判断是否之后全是0.
						for (int i = tempcount; i < 4; i++)
							if (bit[i] != 0)
								alwayszero = 0;
						if (!alwayszero)
							//如果不是全部是0,则输出一个0且将第一个0状态置为0.
							print(bit[tempcount]);
						firstzero = 0;
					}
				}
			}
		}
	}
}
           

​ 上面的函数是重点. 当实现了上一个函数 , 下一个函数就好写多了. 下面我们写从1,0000到9999,9999的输出函数.

​ 这里需要探讨这样的问题. “一万零一十"的问题 , 什么时候会出现这个0呢? 是当万位一下的数小于1000的时候会输出这样的"零”. 同样的 , 当万位之后的部分为0时 , 则不读这个"零". 直接读作"一万".

​ 那么 , 归纳如下. 首先我们将数字分为万以下和万以上的部分

10 , 1234 10,1234 10,1234

​ 如果万位以上数字不为0 , 对于万以上的单位 , 读出后加上"万"字.

​ 然后对于万以后的部分 , 如果它不等于0的话 , 进一步进行判断. 若它小于1000 , 则输出"零"后再读这部分数 , 否则直接读出这部分数. 代码如下.

void tenthousandmaxprint(int n) {
	int n1 = n / 10000;
	int n2 = n % 10000;
	if (n1 != 0) {
		thousandmaxprint(n1);
		printf("万");
	}
	if (n2 != 0) {
		if (n2 < 1000);
			printf("零");
		thousandmaxprint(n2);
	}
}
           

​ 对于一亿到一万亿之间的数 , 方法和读万的方法基本是一致的. 上代码.

void hundredbillionmaxprint(int n) {
	int n1 = n / 100000000;
	int n2 = n % 100000000;
	thousandmaxprint(n1);
	printf("亿");
	if (n2 != 0)
		tenthousandmaxprint(n2);
}
           

​ 这就是这个程序的大概思路了. 还是比较清晰的 , 当然有的地方因为我的文笔问题可能会语义不清 , 但是我都能写出来的东西. 我相信大家一定都能写出来.

​ 最后奉上黏贴可运行的代码.

#include<stdio.h>

/*
print函数负责打印0到9的中文大写.
thousandmaxprint实现不超过一万的数的中文输出.
tenthousandmaxprint实现不超过一亿的数的中文输出.
hundredbillionmaxprint实现不超过一万亿的中文输出.
日常用到中文输出的大部分是财务系统的账目大写,一般
不会超过一万亿.
*/
void print(int n);
void thousandmaxprint(int n);
void tenthousandmaxprint(int n);
void hundredbillionmaxprint(int n);

/*
主程序.
*/
int main() {
	int n;
	printf("输入一个数字的小写后回车可以输出中文写法\n");
	scanf("%d", &n);
	if (n >= 100000000)
		hundredbillionmaxprint(n);
	else{
		if (n >= 10000)
			tenthousandmaxprint(n);
		else
			thousandmaxprint(n);
	}
	return 0;
}

void print(int n) {
	if (n == 0)
		printf("零");
	if (n == 1)
		printf("一");
	if (n == 2)
		printf("二");
	if (n == 3)
		printf("三");
	if (n == 4)
		printf("四");
	if (n == 5)
		printf("五");
	if (n == 6)
		printf("六");
	if (n == 7)
		printf("七");
	if (n == 8)
		printf("八");
	if (n == 9)
		printf("九");
}

void thousandmaxprint(int n) {
	int bit[4] = { 0,0,0,0 };
	bit[0] = n / 1000;
	bit[1] = n % 1000 / 100;
	bit[2] = n % 100 / 10;
	bit[3] = n % 10;
	int start = 0;
	//开始状态变量,当其为1时才会开始打印
	int firstzero = 1;
	//寻找中间的第一个0,输出后会置为0
	int alwayszero = 1;
	//是否从第一个0开始全部是0

	//如果是0
	if (n == 0)
		print(n);
	else {
		//开始遍历
		for (int tempcount = 0; tempcount < 4; tempcount++) {
			if (bit[tempcount] != 0 || tempcount == 3)
				//寻找到最后一位或已经遍历到最后一位
				start = 1;
			if (start) {
				if (bit[tempcount] != 0) {
					if (tempcount == 0) {
						print(bit[tempcount]);
						printf("千");
					}
					if (tempcount == 1) {
						print(bit[tempcount]);
						printf("百");
					}
					if (tempcount == 2) {
						print(bit[tempcount]);
						printf("十");
					}
					if (tempcount == 3) {
						print(bit[tempcount]);
					}
				}
				else {
					if (firstzero && tempcount < 3) {
						//如果是第一个0且不是最末位,则判断是否之后全是0.
						for (int i = tempcount; i < 4; i++)
							if (bit[i] != 0)
								alwayszero = 0;
						if (!alwayszero)
							//如果不是全部是0,则输出一个0且将第一个0状态置为0.
							print(bit[tempcount]);
						firstzero = 0;
					}
				}
			}
		}
	}
}

/*
分离万以上和万以下的部分应用上面定义好的函数.
*/
void tenthousandmaxprint(int n) {
	int n1 = n / 10000;
	int n2 = n % 10000;
	if (n1 != 0) {
		thousandmaxprint(n1);
		printf("万");
	}
	if (n2 != 0) {
		if (n2 < 1000);
			printf("零");
		thousandmaxprint(n2);
	}
}
/*
原理基本同上.
*/
void hundredbillionmaxprint(int n) {
	int n1 = n / 100000000;
	int n2 = n % 100000000;
	thousandmaxprint(n1);
	printf("亿");
	if (n2 != 0)
		tenthousandmaxprint(n2);
}
           

​ 运行结果

阿拉伯数字转换成中文读法的C语言程序

后记

​ 完成以后在CSDN查了一下 , 发现这样的代码有很多 , 可能不是最聪明的方法 , 但希望是最能令我这种"蠢人"理解的方法.

继续阅读