问题描述
Given an integer with no more than 9 digits, you are supposed to read it in the traditional Chinese way. Output Fu first if it is negative. For example, -123456789 is read as Fu yi Yi er Qian san Bai si Shi wu Wan liu Qian qi Bai ba Shi jiu. Note: zero (ling) must be handled correctly according to the Chinese tradition. For example, 100800 is yi Shi Wan ling ba Bai.
输入格式
Each input file contains one test case, which gives an integer with no more than 9 digits.
输出格式
For each test case, print in a line the Chinese way of reading the number. The characters are separated by a space and there must be no extra space at the end of the line.
输入样例1
-123456789
(结尾无空行)
输出样例1
Fu yi Yi er Qian san Bai si Shi wu Wan liu Qian qi Bai ba Shi jiu
(结尾无空行)
输入样例2
100800
(结尾无空行)
输出样例2
yi Shi Wan ling ba Bai
(结尾无空行)
思路
- 输入样例先用整数n接收,判断正负,若为特例0则直接输出 ling 结束函数,若为负则先输出 “Fu” 并将n变成正数,得到绝对值n;
- do…while 循环将整数每一位依次存放在二维数组num[3][5] 中,每一行放四位,最后以 ‘\0’ 结尾,例如 n = 1234567,则二维数组num[][] = { {“7654”} ,{“321”} };
- 从后往前遍历二维数组。每行第 i 个字符输出后再输出对应单位 carry2[i] 。
C语言代码
#include<stdio.h>
#include<string.h>
char carry1[3][7] = {"\0"," Wan"," Yi"};
char carry2[4][7] = {"\0"," Shi"," Bai"," Qian"};
char trans[10][5] = {"ling","yi","er","san","si","wu","liu","qi","ba","jiu"};
int main(){
int n, row = 0, col = 0;
char num[3][5];
bool jud = false; //记录n是否是负数
scanf("%d", &n);
//特殊处理特例0
if(n==0) {
printf("ling");
return 0;
}
//当n为负数时
if(n < 0){
printf("Fu");
jud = true;
n = -n;
}
//依次将n中每一位数字以字符形式存放在二维数组对应的位置上
do{
num[row][col++] = n % 10 + '0';
if(col % 4 == 0){ //每行存放四个字符,并以'\0'结束
num[row][col] = '\0';
col = 0;
row++;
}
n = n / 10;
}while(n != 0);
if(col == 0) //位数正好整除4
num[row-1][5] = '\0';
else{ //位数取余4不为0时,最后一位的下一个字符赋值'\0'
num[row][col] = '\0';
row++;
}
//遍历二维数组,输出对应的中文数字
for(int i = row-1; i >= 0; i--){
int len = strlen(num[i]);
bool carry_out = true; //记录是否应该输出carry1[]中的单位
for(int j = len-1; j >= 0; j--){
if(num[i][j] != '0'){ //存放的对应字符不为'0'
int temp = num[i][j] -'0';
if(i == row-1 && j == len-1 && jud) //n<0且输出第一个字符时
printf(" %s", trans[temp]); //前面带空格
else if(i == row-1 && j == len-1) //n>0且输出第一个字符时
printf("%s", trans[temp]); //前面不带空格
else
printf(" %s", trans[temp]);//其他情况,字符前面都自带空格
}
else if(j == 3){ //第3位置的字符为0时
if(num[i][2] != '0' || num[i][1] != '0' || num[i][0] != '0') //后面字符不都为'0'时
printf(" ling");
else{ //第i行表示的数字为0000时
carry_out = false;
break;
}
}
else if(j == 2){ //第2位置的字符为'0'时
if(num[i][3] != '0' && num[i][1] != '0') //为"X0X-"时
printf(" ling");
else if(num[i][3] != '0' && num[i][2] == '0' && num[i][1] == '0' && num[i][0] != '0'){
//为'X00X'时
printf(" ling");
j--;
}
}
else if(j == 1){ //当第1位置的字符为'0'时
if(num[i][2] != '0' && num[i][0] != '0') //为'-X0X'时
printf(" ling");
}
if(j != 0 && num[i][j] != '0') //每行第0个字符且不为'0'时
printf("%s", carry2[j]);
}
if(row != 0 && carry_out) //第i行字符不为'0000'且不是第0行时
printf("%s", carry1[i]);
}
return 0;
}
注意:
- 因为二维数组每一行的第0个字符若为‘0’不输出 ‘ling’ 所以注意特例0,需要单独考虑;
- 对于’0’字符是否需要输出中文读音的问题需要考虑全面;
- 对整数进行字符化处理时,注意末尾‘\0’的结束问题。
思路优化
- 将数字按照字符串的形式处理,并设置 left 和 right 下标处理数字的每一小节(个节、万节、亿节),left 指向输出的位,right指向输出节的个位;
- 对于 ‘ling’ 的输出采用累积形式,首次遇到0令 flag = true表示存在累积的0;遇到非0时,先判断 flag是否为true,若是,则先输出 ‘ling’ 再输出对应中文及位号。处理完一小节再输出万或者亿。
优化C语言代码
#include<stdio.h>
#include<string.h>
char num[10][5] = {"ling","yi","er","san","si","wu","liu","qi","ba","jiu"};
char wei[5][5] = {"Shi","Bai","Qian","Wan","Yi"};
int main(){
char str[15];
scanf("%s", str);
int len = strlen(str);
int left = 0, right = len - 1;
if(str[0] == '-'){ //若输入为负数
printf("Fu");
left++; //left指向下一个字符
}
while(left + 4 <= right) //找到第一个节(个节、万节、亿节)
right -= 4;
while(left < len){ //循环输出直到left遍历完整个字符串
bool flag = false; //flag == false 表示没有累积的0
bool isPrint = false; // isPrint == false 表示给小节没有输出过其中的位
while(left <= right){ //遍历一小节
if(left > 0 && str[left] =='0') //如果当前位位0
flag = true;
else{
if(flag == true){ //如果存在累积0
printf(" ling");
flag = false;
}
if(left > 0) printf(" "); //只要不是正数的首位,都在输出前先输出一个空格
printf("%s", num[str[left]-'0']);
isPrint = true; //至少有一位数字被输出
if(left != right)
printf(" %s", wei[right-left-1]); //除了个位,输出十千百
}
left++; //left向右移动一位
}
if(isPrint == true && right != len-1) //只要不是个节或没有输出的节,输出万亿
printf(" %s", wei[(len-1-right)/4 + 2]);
right += 4; //right向后移动4位
}
return 0;
}
对于分区域的字符串遍历可以采用下标 left,right 等形式标记遍历的位置及每一区域的分界处