PAT (Advanced Level) Practice 1082 Read Number in Chinese用拼音以中文方式读出数字

一、概述

给出一个不超过九位的数字,用拼音将它的汉语读法写出。

我觉得算是很复杂的一道题,它的复杂不在算法上的复杂,而在情况之多,极为复杂。

最开始的时候,我轻视了这道题,安安分分的一位一位向后移,取余,除十判断输出,但是在写的过程中发现许多种情况都需要判断,一项一项判断会弄得很晕,不知道什么时候该如何输出。然后才发现这道题的坑爹之处。这时候我已经被什么时候输出ling什么时候输出wan什么时候留空格什么时候不留弄晕了。于是狠下心来,采用了最稳妥也是最蠢最复杂的方法:将每一种情况都写出来,用if分别判断。写完之后我对着代码哭笑不得,这代码除了AC以外毫无优点,考场上肯定不会给我这么长的时间去梳理逻辑,我也很可能会落下几种情况,那样就gg了。效率也很是低下,而且很死板,变成十位十一位就不会输出了,可以说是完全的应试代码,鄙视自己。好在它逻辑清晰,很容易就可以看懂(废话,错误情况就再加一个if肯定清晰啊)。

坑点:

80008000(第二三四个零不输出ling)

0(输出ling)

8(输出ba)

100000000(输出yiyi)

80000008(输出baqianwanlingba)

800000008(输出bayilingba,没有wan)

 

二、分析

为了易于分析不同情况,我选择将数字全部变为十位,不足十位的补零,当然首位是符号位。

有以下几种情况:

我们以标志位为第0位,亿位为第一位,个位为第九位。

以第n位为例:

我们定义一个输出ling的标志位isZero,如果该标志位为1,那么说明前面已经输出过ling了,之后遇到0就不要输出ling,这是为了防止8008输出为八千零零八的情况。

如果该位非零,那么看它后面的所有位,

如果所有位都为零,输出的时候最后不加空格;

如果有至少一位不为零,那么输出的时候加空格;

之后置isZero为0,这说明后面遇到0要输出ling。

如果该位为零,那么看它后面所有位,

如果所有位都为零,不输出;

如果有至少一位不为零,那么继续判断isZero,

如果isZero为1,不输出;

如果isZero为0,输出ling;

之后置isZero为1,这说明后面遇到0不再输出ling。

代码如下:

case 6:
    if (_num[6] != '0')//第六位如果不是零,直接输出,同时置输出ling标志位为0
    {
	    if (_num[7] != '0' || _num[8] != '0' || _num[9] != '0')
		    cout << number[_num[i] - 48] << " " << "Qian ";
    	else
    		cout << number[_num[i] - 48] << " " << "Qian";
	    isZero = 0;
    }
    else
    {
	    if (isZero == 1)
		    ;
    	else
	    {
    	    if (_num[7] != '0' || _num[8] != '0' || _num[9] != '0')
	        {
		        cout << "ling ";//输出ling
		        isZero = 1;//输出ling标志位置一
    	    }
        }
    }
    break;
case 7:
	if (_num[7] != '0')//第七位如果不是零,直接输出,同时置输出ling标志位为0
	{
		if (_num[8] != '0' || _num[9] != '0')
			cout << number[_num[i] - 48] << " " << "Bai ";
		else
			cout << number[_num[i] - 48] << " " << "Bai";
			isZero = 0;
	}
	else
	{
		if (isZero == 1)
			;
		else
		{
			if (_num[8] != '0' || _num[9] != '0')
			{
				cout << "ling ";//输出ling
				isZero = 1;//输出ling标志位置一
			}
		}
	}
    break;
case 8:
	if (_num[8] != '0')//第八位如果不是零,直接输出,同时置输出ling标志位为0
	{
		if (_num[9] != '0')
			cout << number[_num[i] - 48] << " " << "Shi ";
		else
			cout << number[_num[i] - 48] << " " << "Shi";
		isZero = 0;
	}
	else
	{
		if (isZero == 1)
			;
		else
		{
			if (_num[9] != '0')
			{
				cout << "ling ";//输出ling
				isZero = 1;//输出ling标志位置一
			}
		}
	}
    break;

特殊情况:

第二三四五位,不为零时输出都要加空格,因为这几位不为零时wan必定输出,wan后不加空格即可;

同时,三四五位有一位为零时,以第三位为零为例,

如果它后面有一位不为零,要判断不为零的这位是不是第四位第五位,

如果第四位第五位均为零,那么第三位的零也不输出ling,这是为了防止80000000输出为八千零万的情况。

代码如下:

case 2:
	if (_num[2] != '0')//第二位如果是不是零,直接输出。eg.123456789
	{
		//if (_num[3] != '0' || _num[4] != '0' || _num[5] != '0' || _num[6] != '0' || _num[7] != '0' || _num[8] != '0' || _num[9] != '0')
			//cout << number[_num[i] - 48] << " " << "Qian ";
		//else
		cout << number[_num[i] - 48] << " " << "Qian ";
		isZero = 0;
	}
	else//第二位如果是零,那么如果第一位是零,则什么也不做;如果第一位不是零,继续判断。如果后面有非零数字,输出ling,否则,什么也不做。eg.123456789,103456789,100000000
	{
		if (_num[1] == '0')
			;
		else
		{
			if (_num[3] != '0' || _num[4] != '0' || _num[5] != '0' || _num[6] != '0' || _num[7] != '0' || _num[8] != '0' || _num[9] != '0')
			{
				cout << "ling ";//输出ling
				isZero = 1;//输出ling标志位置一
			}
		}
	}
    break;
case 3:
	if (_num[3] != '0')//第三位如果不是零,直接输出,同时置输出ling标志位为0
	{
		//if (_num[4] != '0' || _num[5] != '0' || _num[6] != '0' || _num[7] != '0' || _num[8] != '0' || _num[9] != '0')
			//cout << number[_num[i] - 48] << " " << "Bai ";
		//else
			cout << number[_num[i] - 48] << " " << "Bai ";
		isZero = 0;
	}
	else //第三位如果是零,继续判断
	{
		if (isZero == 1)//之前已经输出过ling了,即:这一位的0是一串连续的0中的不是第一个,eg.100456789,那么这个零就不用输出ling了
			;
		else//这说明这个0是第一个0,如果这个0后面还有非零数字,eg.120456789和120000000,输出ling,但是注意,80008000时,应该是八千万八千,不是八千零万八千
		{
			if (_num[4] != '0' || _num[5] != '0' || _num[6] != '0' || _num[7] != '0' || _num[8] != '0' || _num[9] != '0')
			{
				if (_num[4] == '0' && _num[5] == '0')
					;
				else
				{
					cout << "ling ";//输出ling
					isZero = 1;
				}//输出ling标志位置一
			}
		}
	}
	break;
case 4:
	if (_num[4] != '0')//第四位如果不是零,直接输出,同时置输出ling标志位为0
	{
		//if (_num[5] != '0' || _num[6] != '0' || _num[7] != '0' || _num[8] != '0' || _num[9] != '0')
		    //cout << number[_num[i] - 48] << " " << "Shi ";
		//else
			cout << number[_num[i] - 48] << " " << "Shi ";
		isZero = 0;
	}
	else
	{
		if (isZero == 1)
			;
		else//这说明这个0是第一个0
		{
			if (_num[5] != '0' || _num[6] != '0' || _num[7] != '0' || _num[8] != '0' || _num[9] != '0')
			{
				if (_num[5] == '0')
					;
				else
				{
					cout << "ling ";//输出ling
					isZero = 1;
				}//输出ling标志位置一
			}
		}
	}
    break;

第五位的wan,并不是所有的时候都输出的,

当第五位不为0时,要输出wan,

为零时,看第二三四位,

如果这三位都为零,那么wan就不输出,

如果不为零,那么第五位的零不输出,只输出wan。

代码如下:

case 5:
	if (_num[5] != '0')//第五位如果不是零,直接输出,同时置输出ling标志位为0,注意第五位是特殊位,因为这个wan的输出有特例,如果2345位都是0,那么wan就不输出
	{
		if (_num[6] != '0' || _num[7] != '0' || _num[8] != '0' || _num[9] != '0')
			cout << number[_num[i] - 48] << " " << "Wan ";
		else
			cout << number[_num[i] - 48] << " " << "Wan";
		isZero = 0;
	}
	else
	{
		if (_num[2] == '0'&&_num[3] == '0'&&_num[4] == '0'&&_num[5] == '0')//2345位都是0,eg.100004567
			;
		else
		{
			if (_num[6] != '0' || _num[7] != '0' || _num[8] != '0' || _num[9] != '0')
				cout << "Wan ";
			else
				cout << "Wan";
		}
	}
	break;

第九位不为零时,正常输出,为零时,

如果前面全是零,那么输出ling,即输入的为0,

如果前面有一位不为零,那么不输出。

代码如下:

case 9:
	if (_num[9] != '0')//第九位如果不是零,直接输出
		cout << number[_num[i] - 48];
	else
	{
		if(_num[1] == '0' && _num[2] == '0' && _num[3] == '0' && _num[4] == '0' && _num[5] == '0' && _num[6] == '0' && _num[7] == '0' && _num[8] == '0')
			cout << number[_num[i] - 48];
	}
	break;

同时要注意isZero的初值应为1,这是为了防止8输出成零零八的情况。

这样一来,检查点应该可以全过了。

三、总结

本题逻辑分支较多,需要耐心梳理,梳理清楚也就好做得多了,使用多个标志位可以不必像我一样每位分别判断,但是总结出各种标志位也是不容易的。总而言之,自己AC还是很高兴的。就是看别人的代码只有几十行而我的有足足二百多行很是自卑(大括号换行顶了好多行呢)。

PS:代码如下

#include<stdio.h>
#include<string>
#include<iostream>
using namespace std;
char *ch[] = { "Fu","Yi","Qian","Bai","Shi","Wan","Qian","Bai","Shi","Ge"};
char *number[] = { "ling","yi","er","san","si","wu","liu","qi","ba","jiu" };
int main()
{
	string num;
	cin >> num;
	char _num[10] = { '0','0','0','0','0','0','0','0','0','0'};
	int m;
	int length = num.length();
	if (num[0] == '-')
	{
		_num[0] = '-';
		for (m = length - 1; m > 0; m--)
		{
			_num[10 - length + m] = num[m];
		}
	}
	else
	{
		for (m = length - 1; m >= 0; m--)
		{
			_num[10 - length + m] = num[m];
		}
	}//首先,把不足十位的数字通过在前面补零变成十位
	int i;
	int isZero = 1;
	for (i = 0; i < 10; i++)
	{
		switch (i)
		{
		case 0:
			if (_num[0] == '-')//是否是负数
				cout << "Fu ";
			break;
		case 1:
			if (_num[1] != '0')//第一位如果不是零,直接输出。eg.123456789
			{
				if(_num[2]!= '0' ||_num[3] != '0' || _num[4] != '0' || _num[5] != '0' || _num[6] != '0' || _num[7] != '0' || _num[8] != '0' || _num[9] != '0')
					cout << number[_num[i] - 48] << " " << "Yi ";
				else
					cout << number[_num[i] - 48] << " " << "Yi";
				isZero = 0;
			}
			break;//第一位如果是零,什么也不做
		case 2:
			if (_num[2] != '0')//第二位如果是不是零,直接输出。eg.123456789
			{
				//if (_num[3] != '0' || _num[4] != '0' || _num[5] != '0' || _num[6] != '0' || _num[7] != '0' || _num[8] != '0' || _num[9] != '0')
					//cout << number[_num[i] - 48] << " " << "Qian ";
				//else
					cout << number[_num[i] - 48] << " " << "Qian ";
				isZero = 0;
			}
			else//第二位如果是零,那么如果第一位是零,则什么也不做;如果第一位不是零,继续判断。如果后面有非零数字,输出ling,否则,什么也不做。eg.123456789,103456789,100000000
			{
				if (_num[1] == '0')
					;
				else
				{
					if (_num[3] != '0' || _num[4] != '0' || _num[5] != '0' || _num[6] != '0' || _num[7] != '0' || _num[8] != '0' || _num[9] != '0')
					{
						cout << "ling ";//输出ling
						isZero = 1;//输出ling标志位置一
					}
				}
			}
			break;
		case 3:
			if (_num[3] != '0')//第三位如果不是零,直接输出,同时置输出ling标志位为0
			{
				//if (_num[4] != '0' || _num[5] != '0' || _num[6] != '0' || _num[7] != '0' || _num[8] != '0' || _num[9] != '0')
					//cout << number[_num[i] - 48] << " " << "Bai ";
				//else
					cout << number[_num[i] - 48] << " " << "Bai ";
				isZero = 0;
			}
			else //第三位如果是零,继续判断
			{
				if (isZero == 1)//之前已经输出过ling了,即:这一位的0是一串连续的0中的不是第一个,eg.100456789,那么这个零就不用输出ling了
					;
				else//这说明这个0是第一个0,如果这个0后面还有非零数字,eg.120456789和120000000,输出ling,但是注意,80008000时,应该是八千万八千,不是八千零万八千
				{
					if (_num[4] != '0' || _num[5] != '0' || _num[6] != '0' || _num[7] != '0' || _num[8] != '0' || _num[9] != '0')
					{
						if (_num[4] == '0' && _num[5] == '0')
							;
						else
						{
							cout << "ling ";//输出ling
							isZero = 1;
						}//输出ling标志位置一
					}
				}
			}
			break;
		case 4:
			if (_num[4] != '0')//第四位如果不是零,直接输出,同时置输出ling标志位为0
			{
				//if (_num[5] != '0' || _num[6] != '0' || _num[7] != '0' || _num[8] != '0' || _num[9] != '0')
					//cout << number[_num[i] - 48] << " " << "Shi ";
				//else
					cout << number[_num[i] - 48] << " " << "Shi ";
				isZero = 0;
			}
			else
			{
				if (isZero == 1)
					;
				else//这说明这个0是第一个0
				{
					if (_num[5] != '0' || _num[6] != '0' || _num[7] != '0' || _num[8] != '0' || _num[9] != '0')
					{
						if (_num[5] == '0')
							;
						else
						{
							cout << "ling ";//输出ling
							isZero = 1;
						}//输出ling标志位置一
					}
				}
			}
			break;
		case 5:
			if (_num[5] != '0')//第五位如果不是零,直接输出,同时置输出ling标志位为0,注意第五位是特殊位,因为这个wan的输出有特例,如果2345位都是0,那么wan就不输出
			{
				if (_num[6] != '0' || _num[7] != '0' || _num[8] != '0' || _num[9] != '0')
					cout << number[_num[i] - 48] << " " << "Wan ";
				else
					cout << number[_num[i] - 48] << " " << "Wan";
				isZero = 0;
			}
			else
			{
				if (_num[2] == '0'&&_num[3] == '0'&&_num[4] == '0'&&_num[5] == '0')//2345位都是0,eg.100004567
					;
				else
				{
					if (_num[6] != '0' || _num[7] != '0' || _num[8] != '0' || _num[9] != '0')
						cout << "Wan ";
					else
						cout << "Wan";
				}
			}
			break;
		case 6:
			if (_num[6] != '0')//第六位如果不是零,直接输出,同时置输出ling标志位为0
			{
				if (_num[7] != '0' || _num[8] != '0' || _num[9] != '0')
					cout << number[_num[i] - 48] << " " << "Qian ";
				else
					cout << number[_num[i] - 48] << " " << "Qian";
				isZero = 0;
			}
			else
			{
				if (isZero == 1)
					;
				else
				{
					if (_num[7] != '0' || _num[8] != '0' || _num[9] != '0')
					{
						cout << "ling ";//输出ling
						isZero = 1;//输出ling标志位置一
					}
				}
			}
			break;
		case 7:
			if (_num[7] != '0')//第七位如果不是零,直接输出,同时置输出ling标志位为0
			{
				if (_num[8] != '0' || _num[9] != '0')
					cout << number[_num[i] - 48] << " " << "Bai ";
				else
					cout << number[_num[i] - 48] << " " << "Bai";
				isZero = 0;
			}
			else
			{
				if (isZero == 1)
					;
				else
				{
					if (_num[8] != '0' || _num[9] != '0')
					{
						cout << "ling ";//输出ling
						isZero = 1;//输出ling标志位置一
					}
				}
			}
			break;
		case 8:
			if (_num[8] != '0')//第八位如果不是零,直接输出,同时置输出ling标志位为0
			{
				if (_num[9] != '0')
					cout << number[_num[i] - 48] << " " << "Shi ";
				else
					cout << number[_num[i] - 48] << " " << "Shi";
				isZero = 0;
			}
			else
			{
				if (isZero == 1)
					;
				else
				{
					if (_num[9] != '0')
					{
						cout << "ling ";//输出ling
						isZero = 1;//输出ling标志位置一
					}
				}
			}
			break;
		case 9:
			if (_num[9] != '0')//第九位如果不是零,直接输出
				cout << number[_num[i] - 48];
			else
			{
				if(_num[1] == '0' && _num[2] == '0' && _num[3] == '0' && _num[4] == '0' && _num[5] == '0' && _num[6] == '0' && _num[7] == '0' && _num[8] == '0')
					cout << number[_num[i] - 48];
			}
			break;
		}

		/*if (_num[i] == '0')
		{
			isZero = 1;
			continue;
		}
		if (isZero == 1)
		{
			cout << "ling ";
			isZero = '0';
		}
		if(i==0)
			if (_num[0] == '-')
			{
				cout << "Fu ";
				continue;
			}
		else
		{
			if (i != length - 1)
				cout << number[_num[i] - 48] << " " << ch[length - i - 2];
			else
				cout << " " << number[_num[i] - 48];
		}
		if (_num[0] == '-')
		{
			if (length == 10)
			{
				if (i == 1)
					cout << " Yi";
				if (i == 5)
					cout << " Wan";
			}
			if (length <= 9 && length >= 6)
				if (i == length - 5)
					cout << " Wan";
		}
		else
		{
			if (length == 9)
			{
				if (i == '0')
					cout << " Yi";
				if (i == 4)
					cout << " Wan";
			}
			if (length <= 8 && length >= 5)
				if (i == length - 5)
					cout << " Wan";
		}*/
	}
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值