{ }codelper
defining functionsbuilding strings64-bit integersP0200

Reading numbers in Korean

Like an amount written on a cheque, build the string that reads a non-negative integer in Korean (Hangul). The digits 1 to 9 are read 일, 이, 삼, 사, 오, 육, 칠, 팔, 구 in that order. 0 is read "영".
A nonzero number is read by the rules below, and "영" is never written while reading it. First group the number into blocks of four digits starting from the right end.
From the right, they are the block with no unit, the 만 block, the 억 block and the 조 block. A block (1 to 9999) is read in the order thousands, hundreds, tens, ones. At the thousands, hundreds and tens places, a digit 0 skips that place, a digit 1 writes only "천", "백" or "십", and a digit 2 to 9 writes the digit's name followed by "천", "백" or "십". The ones place is skipped if it is 0; otherwise write just the digit's name. A block whose value is 0 is skipped entirely, unit included. A block whose value is not 0 is read and then followed by its unit (조, 억, 만). However, if the 만 block's value is 1, write only "만", not "일만".
If the 억 or 조 block's value is 1, write "일억" or "일조". Join all the blocks from the left with no spaces. The first line gives the count n, and the next n lines give one number each. For each number print the string that reads it, on its own line. Try writing one function that reads 1 to 9999, and a function that reads the whole number by calling it again for each block.

Input
1 ≤ n ≤ 1,000, 0 ≤ number ≤ 999,999,999,999,999
Output
n lines: each number read in Korean
Example 1 · stdin
7
0
11
10000
10001
110000
100000000
1234567890123
stdout
영
십일
만
만일
십일만
일억
일조이천삼백사십오억육천칠백팔십구만백이십삼
main.py
Input (stdin)

When you run, these lines are fed to input()/stdin in order (the program doesn't stop to ask).

$ Ready

Open this on a computer to write and run code. On mobile you can read the problem and the solutions.

In other languagesShow solutions by language · 8 languages

The same rule is used four times (조, 억, 만 and the rest), so the key is one function that reads 1 to 9999, called again for each block.
Defining a function: Python def read_group(n):, JS function readGroup(n), TS adds types as in function readGroup(n: number): string, Java and C# use a static method inside a class, and in C the function must appear before it is used (or be declared with a prototype).
Craykon defines it without a keyword, readGroup(n) { … return out; }, and the outer digit-name list can be read inside the function.
Joining strings differs too: Python, JS and Craykon +, Java and C# StringBuilder, C++ std::string with +=, and C appends bytes with strcat; one Hangul syllable is 3 bytes in UTF-8, so make the buffer roomy.
999 trillion exceeds int (about 2.1 billion), so Java and C# read it as long, C and C++ as long long.
Numbers in JS, TS and Craykon are exact integers up to 2^53 (about 9,007 trillion), so 999 trillion is fine; take quotients with Python //, JS Math.floor, Craykon Mathf.Quot.
Six traps: ① Reading the 1 before 십, 백, 천 makes 10 "일십" and 100 "일백".
② When the 만 block is 1 it is "만", not "일만" (10001 is "만일").
③ But do not apply that rule to 억 and 조 too.
1억 is "일억" and 1조 is "일조".
④ Adding the unit of a block whose value is 0 turns 1억 into "일억만".
⑤ For 0 every block is empty and you get an empty line, so return "영" separately.
⑥ Reading with Java Integer.parseInt throws from 2147483648 on.

Pythonmain.py · 33 lines
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 lines
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 lines
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 lines
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 lines
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 lines
#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 lines
#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 lines
숫자이름 = ["", "일", "이", "삼", "사", "오", "육", "칠", "팔", "구"]; // 1 ~ 9999를 읽는다. 십·백·천 앞의 1은 읽지 않는다(십, 백, 천)네자리읽기(n){    out = "";    자리이름 = ["천", "백", "십"];    자리크기 = [1000, 100, 10];    for (i = 0; i < 3; i++)    {        d = Mathf.Quot(n, 자리크기[i]) % 10;        if (d == 1)        {            out = out + 자리이름[i];        }        else if (d > 1)        {            out = out + 숫자이름[d] + 자리이름[i];        }    }    return out + 숫자이름[n % 10];} // 999조까지는 2^53보다 작아서 수가 정확하다수읽기(x){    if (x == 0)    {        return "영";    }    out = "";    묶음이름 = ["조", "억", "만", ""];    묶음크기 = [1000000000000, 100000000, 10000, 1];    for (i = 0; i < 4; i++)    {        g = Mathf.Quot(x, 묶음크기[i]) % 10000;        if (g == 0)        {            continue; // 빈 묶음은 단위까지 통째로 건너뛴다        }        if (g == 1 && 묶음이름[i] == "만")        {            out = out + "만"; // 10000은 "일만"이 아니라 "만"        }        else        {            out = out + 네자리읽기(g) + 묶음이름[i];        }    }    return out;} n = Console.ReadLine().ToNumber();for (k = 0; k < n; k++){    Console.WriteLine(수읽기(Console.ReadLine().ToNumber()));}