天天看點

阿拉伯數字轉換成中文讀法的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查了一下 , 發現這樣的代碼有很多 , 可能不是最聰明的方法 , 但希望是最能令我這種"蠢人"了解的方法.

繼續閱讀