PAT_A1082 | Read Number in Chinese

1082 Read Number in Chinese (25point(s))

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.

Input Specification:

Each input file contains one test case, which gives an integer with no more than 9 digits.

Output Specification:

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.

Sample Input 1:

-123456789

 

Sample Output 1:

Fu yi Yi er Qian san Bai si Shi wu Wan liu Qian qi Bai ba Shi jiu

 

Sample Input 2:

100800

 

Sample Output 2:

yi Shi Wan ling ba Bai

这道题我反反复复写了三次,主要是判断是否读零空格输出的处理比较繁琐,导致代码比较乱。

最终写出的这个版本虽然代码有点长,但是很好理解,代码的可读性也比较好。


首先,输入的数字是用字符串储存的,并且记录下原始长度:rel。为了方便是否读零的判断简化下标的移动,可以将输入的数字全都转化成九位数:

比如: 1  - >  000000001

            12345 - > 000012345

也就是不到九位数的用0在前面补齐,此处理的函数代码如下:

/* 将数字用零补齐至亿位 */
void set(char s[]) {
    int len = strlen(s);
    int move = 9 - len;
    /* 向后移动move位 */
    for (int i = len - 1; i >= 0; i--)
        s[i + move] = s[i];
    /* 将前move位补上0 */
    for (int i = 0; i < move; i++)
        s[i] = '0';
}

1、对于负号的处理

判断首字符是否位负号,如果是就输出"Fu",并且将所有位均向前移一位,覆盖掉负号。

 

2、对于是否读零的判断

数字串中的0有的要读有的不要读,这也是这道题的难点和代码的繁琐点,我总结了一下,这个方法应该是最好理解最简单的:

经过上面的处理,我们需要读的数字都是九位数。那么我们可以用一个 bool 型的flag数组,分别对应每一位(从亿位到个位)如果为零是否需要读出

 

① 对于亿位、万位、个位上的0一律不读

 

②对于前面有内容后一位不是0的位,要读;否则不读

对应代码: 

    bool flag[9];  //依次对应每一位(如果为零是否要读出)
    flag[0] = flag[8] = flag[4] = false;
    for (int i = 1; i <= 3; i++)
        flag[i] = rel > 9 - i && number[i + 1] != '0';
    for (int i = 5; i <= 7; i++)
        flag[i] = rel > 9 - i && number[i + 1] != '0';

3、对于空格输出的处理

由于此题的复杂性,需要一个bool型变量 blank 判断是否需要输出空格。主要是在第一次输出的时候不需要前置空格,之后的每一次输出前都要输出空格。所以blank的初值设置为false,即第一次输出前不带有空格;一旦有输出就要改为true,使得之后的输出前都带有空格。

 

此题完整AC代码如下:

//
// Created by LittleCat on 2020/2/10.
//

#include <cstdio>
#include <cstring>

char number[11];
char s[10][6] = {"ling", "yi", "er", "san", "si", "wu", "liu", "qi", "ba", "jiu"};
char byte[4][6] = {" Qian", " Bai", " Shi",""};

/* 将数字用零补齐至亿位 */
void set(char s[]) {
    int len = strlen(s);
    int move = 9 - len;
    /* 向后移动move位 */
    for (int i = len - 1; i >= 0; i--)
        s[i + move] = s[i];
    /* 将前move位补上0 */
    for (int i = 0; i < move; i++)
        s[i] = '0';
}

int main() {

    scanf("%s", number);

    if(number[0] == '0') {
        printf("ling");
        return 0;
    }

    int rel = strlen(number);
    bool blank = false;
    if (number[0] == '-') {
        printf("Fu");
        blank = true;
        /* 全部向前移一位,覆盖负号 */
        for (int i = 0; number[i] != '\0'; i++)
            number[i] = number[i + 1];
    }
    set(number);

    bool flag[9];  //依次对应每一位(如果为零是否要读出)
    flag[0] = flag[8] = flag[4] = false;
    for (int i = 1; i <= 3; i++)
        flag[i] = rel > 9 - i && number[i + 1] != '0';
    for(int i = 5; i <= 7; i++)
        flag[i] = rel > 9 - i && number[i + 1] != '0';


    /* 输出亿 */
    if (number[0] != '0') {
        if (blank)
            putchar(' ');
        printf("%s Yi", s[number[0] - '0']);
        if (!blank)
            blank = true;
    }

    /* 输出万 */
    for(int i = 1; i < 9; i++) {
        if (number[i] != '0') {
            if (blank)
                putchar(' ');
            printf("%s%s", s[number[i] - '0'], byte[(i - 1) % 4]);
            blank = true;
        }
        else if (flag[i]) {
            if (blank)
                putchar(' ');
            printf("ling");
            blank = true;
        }
        if (rel > 4 && i == 4)
            printf(" Wan");
    }

}



end 

欢迎关注个人公众号 鸡翅编程 ”,这里是认真且乖巧的码农一枚。

---- 做最乖巧的博客er,做最扎实的程序员 ----

旨在用心写好每一篇文章,平常会把笔记汇总成推送更新~

在这里插入图片描述

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值