#54967: C語言 討論版


roats1000@gmail.com (Cheng)


#include <stdio.h>
#include <string.h>

#define MAXN 200005      // 輸入數字字串長度上限
#define MAXG 50010       // 最多可切成多少個 4 位群組
#define MAXOUT 4000000    // 輸出緩衝區大小

// 數字表:0~9
const char *dig[2][10] = {
    {"零","一","二","三","四","五","六","七","八","九"},
    {"零","壹","貳","參","肆","伍","陸","柒","捌","玖"}
};

// 個、十、百、千
const char *sunit[2][4] = {
    {"","十","百","千"},
    {"","拾","佰","仟"}
};

// 大單位
const char *bunit[12] = {
    "","萬","億","兆","京","垓","秭","穰","溝","澗","正","載"
};

// 把字串接到結果尾端
void add(char **p, const char *s) {
    while (*s) {
        *(*p)++ = *s;
        s++;
    }
}

// 判斷一整段是否全為 0
int allZero(const char *s) {
    while (*s) {
        if (*s != '0') return 0;
        s++;
    }
    return 1;
}

// 將 1~4 位數字群組轉成中文
void convGroup(const char *g, int t, char *out) {
    char *p = out;
    int len = (int)strlen(g);
    int zeroFlag = 0;   // 是否要補一個「零」

    for (int i = 0; i < len; i++) {
        int d = g[i] - '0';
        int pos = len - 1 - i;   // 0:個位, 1:十位, 2:百位, 3:千位

        if (d == 0) {
            // 只有在已經輸出過非 0 數字後,才可能需要補零
            if (p != out) zeroFlag = 1;
        } else {
            // 前面有 0,先補一個零
            if (zeroFlag) {
                add(&p, dig[t][0]);
                zeroFlag = 0;
            }

            // 輸出數字本身
            add(&p, dig[t][d]);

            // 輸出對應單位
            if (pos > 0) add(&p, sunit[t][pos]);
        }
    }

    *p = '\0';
}

int main() {
    int T;
    char N[MAXN];

    // 每一筆測資直到 EOF
    while (scanf("%d %s", &T, N) == 2) {
        int len = (int)strlen(N);
        int st = 0;

        // 去掉整體前導 0
        while (st < len && N[st] == '0') st++;

        // 如果整串都是 0
        if (st == len) {
            puts(dig[T][0]);
            continue;
        }

        // 將數字從右邊開始每 4 位切一組
        // grp[0] 是最低位那組,grp[cnt-1] 是最高位那組
        char grp[MAXG][5];
        int cnt = 0;

        for (int i = len; i > st; i -= 4) {
            int l = i - 4;
            if (l < st) l = st;

            int gLen = i - l;
            memcpy(grp[cnt], N + l, gLen);
            grp[cnt][gLen] = '\0';
            cnt++;
        }

        // 開始組合答案
        char out[MAXOUT];
        char *p = out;

        int need0 = 0;   // 中間是否跳過整組 0000

        // 從最高位群組往低位群組處理
        for (int i = cnt - 1; i >= 0; i--) {
            // 如果這組全是 0,就先記錄,等下一組非 0 時補零
            if (allZero(grp[i])) {
                need0 = 1;
                continue;
            }

            // 若前面已經輸出過內容,而且:
            // 1. 中間有跳過 0000 群組,或
            // 2. 目前這組本身有前導 0(例如 0500、0010)
            // 就要先補一個「零」
            if (p != out && (need0 || grp[i][0] == '0')) {
                add(&p, dig[T][0]);
            }

            // 轉換目前這組
            char tmp[32];
            convGroup(grp[i], T, tmp);
            add(&p, tmp);

            // 加上大單位:萬、億、兆...
            if (i > 0 && i < 12) {
                add(&p, bunit[i]);
            }

            need0 = 0;
        }

        *p = '\0';
        puts(out);
    }

    return 0;
}