{ }codelper
関数の定義文字列の組み立て64ビット整数P0200

数をハングルで読む

小切手に書く金額のように、0 以上の整数を韓国語(ハングル)で読んだ文字列を作る。
数字 1〜9 は順に 일、이、삼、사、오、육、칠、팔、구 と読む。
0 は "영" と読む。
0 でない数は下の規則で読み、読む途中で "영" は書かない。
まず数を右端から四桁ずつまとめる。
右から順に、単位のないまとまり、만 のまとまり、억 のまとまり、조 のまとまりである。
一つのまとまり(1〜9999)は千の位、百の位、十の位、一の位の順に読む。
千・百・十の位では、数字が 0 ならその位を飛ばし、1 なら "천"・"백"・"십" だけを書き、2〜9 なら数字の名前の後ろに "천"・"백"・"십" を付ける。
一の位は 0 なら飛ばし、そうでなければ数字の名前だけを書く。
値が 0 のまとまりは単位ごとまるごと飛ばす。
値が 0 でないまとまりは、そのまとまりを読んだ後に単位(조、억、만)を付ける。
ただし 만 のまとまりの値が 1 なら "일만" ではなく "만" とだけ書く。
억 と 조 のまとまりの値が 1 なら "일억"・"일조" と書く。
すべてのまとまりを左から空白なしでつなげて書く。
一行目に数の個数 n、続く n 行に数が一つずつ与えられる。
数ごとに読んだ文字列を一行に出力せよ。
1〜9999 を読む関数を一つ作り、その関数をまとまりごとに使い回して数全体を読む関数を作ってみよう。

入力
1 ≤ n ≤ 1,000、0 ≤ 数 ≤ 999,999,999,999,999
出力
n 行:数ごとにハングルで読んだ文字列
例 1 · stdin
7
0
11
10000
10001
110000
100000000
1234567890123
stdout
영
십일
만
만일
십일만
일억
일조이천삼백사십오억육천칠백팔십구만백이십삼
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

同じ規則を四回(조・억・만・残り)使うので、1〜9999 を読む関数を一つ作ってまとまりごとに呼び直すのが要です。
関数の作り方:Python def read_group(n):、JS function readGroup(n)、TS は function readGroup(n: number): string のように型を書き、Java・C# はクラスの中の static メソッド、C は使う前に関数が先に出ていなければなりません(でなければプロトタイプ宣言)。
Craykon はキーワードなしで readGroup(n) { … 返す out; } と作り、外側の数字名のリストも関数の中で読めます。
文字列のつなぎ方も違います:Python・JS・Craykon +、Java・C# StringBuilder、C++ std::string の +=、C は strcat でバイトをつなぎますが、ハングル一文字は UTF-8 で 3 バイトなのでバッファを十分に取ります。
999 兆は int(約 21 億)を超えるので、Java・C# は long、C・C++ は long long で受け取ります。
JS・TS・Craykon の数は 2^53(約 9,007 兆)まで整数が正確なので 999 兆は大丈夫で、商は Python //、JS Math.floor、Craykon 数学.商 で求めます。
落とし穴は六つ:① 십・백・천 の前の 1 を読むと、10 が "일십"、100 が "일백" になります。
② 만 のまとまりが 1 のときは "일만" ではなく "만" です(10001 は "만일")。
③ だからといって 1 を省く規則を 억・조 にも使ってはいけません。
1억 は "일억"、1조 は "일조" です。
④ 値が 0 のまとまりの単位を付けると、1억 が "일억만" になります。
⑤ 0 はまとまりがすべて空になって空行になるので、別に "영" を返します。
⑥ Java の Integer.parseInt で読むと 2147483648 から例外が出ます。

Pythonmain.py · 33 行
DIGIT = ["", "일", "이", "삼", "사", "오", "육", "칠", "팔", "구"]  def read_group(n):    """1 ~ 9999를 읽는다. 십·백·천 앞의 1은 읽지 않는다(십, 백, 천)"""    out = ""    for unit, size in (("천", 1000), ("백", 100), ("십", 10)):        d = n // size % 10        if d == 1:            out += unit        elif d > 1:            out += DIGIT[d] + unit    return out + DIGIT[n % 10]  def read_number(x):    if x == 0:        return "영"    out = ""    for unit, size in (("조", 10 ** 12), ("억", 10 ** 8), ("만", 10 ** 4), ("", 1)):        g = x // size % 10000        if g == 0:            continue  # 빈 묶음은 단위까지 통째로 건너뛴다        if g == 1 and unit == "만":            out += "만"  # 10000은 "일만"이 아니라 "만"        else:            out += read_group(g) + unit    return out  n = int(input())for _ in range(n):    print(read_number(int(input())))
JavaScriptmain.js · 31 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const DIGIT = ["", "일", "이", "삼", "사", "오", "육", "칠", "팔", "구"]; // 1 ~ 9999를 읽는다. 십·백·천 앞의 1은 읽지 않는다(십, 백, 천)function readGroup(n) {  let out = "";  for (const [unit, size] of [["천", 1000], ["백", 100], ["십", 10]]) {    const d = Math.floor(n / size) % 10;    if (d === 1) out += unit;    else if (d > 1) out += DIGIT[d] + unit;  }  return out + DIGIT[n % 10];} // 999조까지는 2^53보다 작아서 Number로도 정확하다function readNumber(x) {  if (x === 0) return "영";  let out = "";  for (const [unit, size] of [["조", 1e12], ["억", 1e8], ["만", 1e4], ["", 1]]) {    const g = Math.floor(x / size) % 10000;    if (g === 0) continue; // 빈 묶음은 단위까지 통째로 건너뛴다    if (g === 1 && unit === "만") out += "만"; // 10000은 "일만"이 아니라 "만"    else out += readGroup(g) + unit;  }  return out;} const n = Number(lines[0]);const out = [];for (let i = 1; i <= n; i++) out.push(readNumber(Number(lines[i])));console.log(out.join("\n"));
TypeScriptmain.ts · 35 行
import { readFileSync } from "node:fs"; const lines: string[] = readFileSync(0, "utf8").split("\n");const DIGIT: string[] = ["", "일", "이", "삼", "사", "오", "육", "칠", "팔", "구"]; // 1 ~ 9999를 읽는다. 십·백·천 앞의 1은 읽지 않는다(십, 백, 천)function readGroup(n: number): string {  let out = "";  const places: [string, number][] = [["천", 1000], ["백", 100], ["십", 10]];  for (const [unit, size] of places) {    const d = Math.floor(n / size) % 10;    if (d === 1) out += unit;    else if (d > 1) out += DIGIT[d] + unit;  }  return out + DIGIT[n % 10];} // 999조까지는 2^53보다 작아서 number로도 정확하다function readNumber(x: number): string {  if (x === 0) return "영";  let out = "";  const groups: [string, number][] = [["조", 1e12], ["억", 1e8], ["만", 1e4], ["", 1]];  for (const [unit, size] of groups) {    const g = Math.floor(x / size) % 10000;    if (g === 0) continue; // 빈 묶음은 단위까지 통째로 건너뛴다    if (g === 1 && unit === "만") out += "만"; // 10000은 "일만"이 아니라 "만"    else out += readGroup(g) + unit;  }  return out;} const n = Number(lines[0]);const out: string[] = [];for (let i = 1; i <= n; i++) out.push(readNumber(Number(lines[i])));console.log(out.join("\n"));
JavaMain.java · 43 行
import java.io.*; public class Main {    static final String[] DIGIT = {"", "일", "이", "삼", "사", "오", "육", "칠", "팔", "구"};    static final String[] PLACE = {"천", "백", "십"};    static final int[] PLACE_SIZE = {1000, 100, 10};    static final String[] GROUP = {"조", "억", "만", ""};    static final long[] GROUP_SIZE = {1_000_000_000_000L, 100_000_000L, 10_000L, 1L};     // 1 ~ 9999를 읽는다. 십·백·천 앞의 1은 읽지 않는다(십, 백, 천)    static String readGroup(int n) {        StringBuilder sb = new StringBuilder();        for (int i = 0; i < 3; i++) {            int d = n / PLACE_SIZE[i] % 10;            if (d == 1) sb.append(PLACE[i]);            else if (d > 1) sb.append(DIGIT[d]).append(PLACE[i]);        }        return sb.append(DIGIT[n % 10]).toString();    }     // 999조는 int(약 21억)를 넘으니 long으로 받는다    static String readNumber(long x) {        if (x == 0) return "영";        StringBuilder sb = new StringBuilder();        for (int i = 0; i < 4; i++) {            int g = (int) (x / GROUP_SIZE[i] % 10000);            if (g == 0) continue; // 빈 묶음은 단위까지 통째로 건너뛴다            if (g == 1 && GROUP[i].equals("만")) sb.append("만"); // 10000은 "일만"이 아니라 "만"            else sb.append(readGroup(g)).append(GROUP[i]);        }        return sb.toString();    }     public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(br.readLine().trim());        StringBuilder out = new StringBuilder();        for (int i = 0; i < n; i++) {            out.append(readNumber(Long.parseLong(br.readLine().trim()))).append('\n');        }        System.out.print(out);    }}
C#Main.cs · 48 行
using System;using System.Text; class Program{    static readonly string[] Digit = { "", "일", "이", "삼", "사", "오", "육", "칠", "팔", "구" };    static readonly (string Unit, int Size)[] Places = { ("천", 1000), ("백", 100), ("십", 10) };    static readonly (string Unit, long Size)[] Groups = { ("조", 1_000_000_000_000L), ("억", 100_000_000L), ("만", 10_000L), ("", 1L) };     // 1 ~ 9999를 읽는다. 십·백·천 앞의 1은 읽지 않는다(십, 백, 천)    static string ReadGroup(int n)    {        var sb = new StringBuilder();        foreach (var (unit, size) in Places)        {            int d = n / size % 10;            if (d == 1) sb.Append(unit);            else if (d > 1) sb.Append(Digit[d]).Append(unit);        }        return sb.Append(Digit[n % 10]).ToString();    }     // 999조는 int(약 21억)를 넘으니 long으로 받는다    static string ReadNumber(long x)    {        if (x == 0) return "영";        var sb = new StringBuilder();        foreach (var (unit, size) in Groups)        {            int g = (int)(x / size % 10000);            if (g == 0) continue; // 빈 묶음은 단위까지 통째로 건너뛴다            if (g == 1 && unit == "만") sb.Append("만"); // 10000은 "일만"이 아니라 "만"            else sb.Append(ReadGroup(g)).Append(unit);        }        return sb.ToString();    }     static void Main()    {        int n = int.Parse(Console.ReadLine()!.Trim());        var output = new StringBuilder();        for (int i = 0; i < n; i++)        {            output.Append(ReadNumber(long.Parse(Console.ReadLine()!.Trim()))).Append('\n');        }        Console.Write(output);    }}
C++main.cpp · 43 行
#include <array>#include <iostream>#include <string>#include <utility> const std::array<std::string, 10> DIGIT = {"", "일", "이", "삼", "사", "오", "육", "칠", "팔", "구"}; // 1 ~ 9999를 읽는다. 십·백·천 앞의 1은 읽지 않는다(십, 백, 천)std::string readGroup(int n) {    const std::array<std::pair<std::string, int>, 3> places = {{{"천", 1000}, {"백", 100}, {"십", 10}}};    std::string out;    for (const auto& [unit, size] : places) {        int d = n / size % 10;        if (d == 1) out += unit;        else if (d > 1) out += DIGIT[d] + unit;    }    return out + DIGIT[n % 10];} // 999조는 int(약 21억)를 넘으니 long long으로 받는다std::string readNumber(long long x) {    if (x == 0) return "영";    const std::array<std::pair<std::string, long long>, 4> groups = {{{"조", 1000000000000LL}, {"억", 100000000LL}, {"만", 10000LL}, {"", 1LL}}};    std::string out;    for (const auto& [unit, size] : groups) {        int g = static_cast<int>(x / size % 10000);        if (g == 0) continue; // 빈 묶음은 단위까지 통째로 건너뛴다        if (g == 1 && unit == "만") out += "만"; // 10000은 "일만"이 아니라 "만"        else out += readGroup(g) + unit;    }    return out;} int main() {    std::ios::sync_with_stdio(false);    int n;    long long x;    std::cin >> n;    for (int i = 0; i < n; i++) {        std::cin >> x;        std::cout << readNumber(x) << "\n";    }}
Cmain.c · 55 行
#include <stdio.h>#include <string.h> // 한글 한 글자는 UTF-8로 3바이트다. 문자열은 그냥 바이트로 이어 붙인다static const char *DIGIT[] = {"", "일", "이", "삼", "사", "오", "육", "칠", "팔", "구"};static const char *PLACE[] = {"천", "백", "십"};static const int PLACE_SIZE[] = {1000, 100, 10};static const char *GROUP[] = {"조", "억", "만", ""};static const long long GROUP_SIZE[] = {1000000000000LL, 100000000LL, 10000LL, 1LL}; // 1 ~ 9999를 읽어 out 끝에 붙인다. 십·백·천 앞의 1은 읽지 않는다(십, 백, 천)void read_group(int n, char *out) {    for (int i = 0; i < 3; i++) {        int d = n / PLACE_SIZE[i] % 10;        if (d == 1) {            strcat(out, PLACE[i]);        } else if (d > 1) {            strcat(out, DIGIT[d]);            strcat(out, PLACE[i]);        }    }    strcat(out, DIGIT[n % 10]);} // 999조는 int(약 21억)를 넘으니 long long으로 받는다void read_number(long long x, char *out) {    out[0] = '\0';    if (x == 0) {        strcpy(out, "영");        return;    }    for (int i = 0; i < 4; i++) {        int g = (int)(x / GROUP_SIZE[i] % 10000);        if (g == 0) continue; // 빈 묶음은 단위까지 통째로 건너뛴다        if (g == 1 && i == 2) {            strcat(out, "만"); // 10000은 "일만"이 아니라 "만"        } else {            read_group(g, out);            strcat(out, GROUP[i]);        }    }} int main(void) {    int n;    long long x;    char out[256]; // 가장 긴 것도 한글 40글자 남짓(120바이트)    scanf("%d", &n);    for (int i = 0; i < n; i++) {        scanf("%lld", &x);        read_number(x, out);        puts(out);    }    return 0;}
Craykonmain.cray · 57 行
숫자이름 = ["", "일", "이", "삼", "사", "오", "육", "칠", "팔", "구"]; // 1 ~ 9999를 읽는다. 십·백·천 앞의 1은 읽지 않는다(십, 백, 천)네자리읽기(n){    out = "";    자리이름 = ["천", "백", "십"];    자리크기 = [1000, 100, 10];    繰り返す (i = 0; i < 3; i++)    {        d = 数学.商(n, 자리크기[i]) % 10;        もし (d == 1)        {            out = out + 자리이름[i];        }        でなければ もし (d > 1)        {            out = out + 숫자이름[d] + 자리이름[i];        }    }    返す out + 숫자이름[n % 10];} // 999조까지는 2^53보다 작아서 수가 정확하다수읽기(x){    もし (x == 0)    {        返す "영";    }    out = "";    묶음이름 = ["조", "억", "만", ""];    묶음크기 = [1000000000000, 100000000, 10000, 1];    繰り返す (i = 0; i < 4; i++)    {        g = 数学.商(x, 묶음크기[i]) % 10000;        もし (g == 0)        {            次へ; // 빈 묶음은 단위까지 통째로 건너뛴다        }        もし (g == 1 && 묶음이름[i] == "만")        {            out = out + "만"; // 10000은 "일만"이 아니라 "만"        }        でなければ        {            out = out + 네자리읽기(g) + 묶음이름[i];        }    }    返す out;} n = コンソール.行読み().数に();繰り返す (k = 0; k < n; k++){    コンソール.書く(수읽기(コンソール.行読み().数に()));}