{ }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(999조 9999억 9999만 9999)
출력
n줄: 수마다 한글로 읽은 문자열
예시 1 · stdin
7
0
11
10000
10001
110000
100000000
1234567890123
stdout
영
십일
만
만일
십일만
일억
일조이천삼백사십오억육천칠백팔십구만백이십삼
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

같은 규칙을 네 번(조·억·만·나머지) 쓰니, 1 ~ 9999를 읽는 함수 하나를 만들어 묶음마다 다시 부르는 게 핵심이에요.
함수 만드는 법: Python def read_group(n):, JS function readGroup(n), TS는 function readGroup(n: number): string처럼 타입을 적고, Java·C#은 클래스 안의 static 메서드, C는 쓰기 전에 함수가 먼저 나와 있어야 해요(아니면 원형 선언).
크레이콘은 키워드 없이 네자리읽기(n) { … 돌려주기 out; }로 만들고, 바깥의 숫자이름 목록도 함수 안에서 읽을 수 있어요.
문자열 잇기도 달라요: Python·JS·크레이콘 +, Java·C# StringBuilder, C++ std::string의 +=, C는 strcat으로 바이트를 붙이는데 한글 한 글자가 UTF-8로 3바이트라 버퍼를 넉넉히 잡아요.
999조는 int(약 21억)를 넘어서 Java·C#은 long, C·C++은 long long으로 받아요.
JS·TS·크레이콘의 수는 2^53(약 9,007조)까지 정수가 정확해서 999조는 괜찮고, 몫은 Python //, JS Math.floor, 크레이콘 수학.몫으로 구해요.
함정 여섯: ① 십·백·천 앞의 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++){    콘솔.쓰기(수읽기(콘솔.줄읽기().수로변환()));}