6
\$\begingroup\$

Goal

You will be given a positive integer number less than 10^20. You must convert it to Korean.

For example, if the input is 12345, the output should be 일만이천삼백사십오.

Technical details (Small)

Let's starts with simple numbers.

// 1 - 9
1 -> 일
2 -> 이
3 -> 삼
4 -> 사
5 -> 오
6 -> 육
7 -> 칠
8 -> 팔
9 -> 구

// 10, 100, 1000
10 -> 십
100 -> 백
1000 -> 천

You can concatenate 2 ~ 9 front of 10, 100, 1000.
However, you should not concatenate 1 front of 10, 100, 1000.

// 20 = 2 * 10
20 -> 이십

// 300 = 3 * 100
300 -> 삼백

// 9000 = 9 * 1000
9000 -> 구천

// 1000 is just 1000
1000 -> 천

For integer less than 10000, below rule is used for pronunciation.

// 1234 = 1000 + 200 + 30 + 4
1234 -> 천이백삼십사

// 1002 = 1000 + 2
1002 -> 천이

// 2048 = 2000 + 40 + 8
2048 -> 이천사십팔

// 510 = 500 + 10
510 -> 오백십

// 13 = 10 + 3
13 -> 십삼

Technical details (Large)

Now let's go to the hard part.

First, you need to know some parts used in larger numbers:

1 0000 -> 만
1 0000 0000 -> 억
1 0000 0000 0000 -> 조
1 0000 0000 0000 0000 -> 경

When Koreans pronounce big numbers

  1. Cut it with width 4
  2. Convert each of them using methods for less than 10000
  3. Combine them with default form of big numbers

Here is some detailed examples. (I added some space to korean for readability)

// 12345678 = 1234 5678
// 1234 -> 천이백삼십사
// 5678 -> 오천육백칠십팔
12345678 -> 천이백삼십사 만 오천육백칠십팔

// 11122223333 = 111 2222 3333
// 111 -> 백십일
// 2222 -> 이천이백이십이
// 3333 -> 삼천삼백삼십삼
11122223333 -> 백십일 억 이천이백이십이 만 삼천삼백삼십삼

// 10900000014 = 109 0000 0014
// 109 -> 백구
// 0000 -> (None)
// 0014 -> 십사
10900000014 -> 백구 억 십사

// 100000000 -> 1 0000 0000
// 1 -> 일
// 0000 -> (None)
// 0000 -> (None)
100000000 -> 일 억

Here are some more examples.

Rule

You can make your program gets input from stdin and output to stdout, or make a function that gets string/integer and returns string.

This is , so answers will be scored in bytes with fewer bytes being better.

\$\endgroup\$
  • 1
    \$\begingroup\$ @JonathanAllan 일억 is correct form of 100000000. is a unit that cannot used alone. \$\endgroup\$ – 0xrgb Feb 17 '18 at 18:14
  • 1
    \$\begingroup\$ Thanks for clarification I've edited the post very slightly for clarity. \$\endgroup\$ – Jonathan Allan Feb 17 '18 at 18:18
  • \$\begingroup\$ Oh well now people are getting inspired on my question. \$\endgroup\$ – Matthew Roh Feb 18 '18 at 7:10
8
\$\begingroup\$

Aheui, 1555 bytes

살밦발따밝따빠따밦발다빠따다빠밞빠따받다빠따밝발따두
수터더떠벋벓떠뻐더벖떠뻐벍뻐터터떠벌벖떠뻐떠벋벎뻐더
방뺘우차빠발발다빠따빠뚜
우노여뗘뻐떠뻐더벌벌썪러
샦우싹어
아삳부
ㅇ아삭뺘우차빠불
ㅇ유어우여려더벌
ㅇ요ㅇ빠받반타탸우처삳뺘우처밝밤뚜
ㅇㅇ우쑨여텨여볋여뗘여뼈여뎌벅떠벓
ㅇ요아삭뺘우차삳빠박탸유처발불
ㅇㅇ우어ㅇ여따뱖볆뚜텨벎떠뻐떠
ㅇ요ㅇ우어쎤여뎌여별여어
ㅇㅇㅇ빠밤탸우처밣빠따밞다뿌
ㅇ요ㅇ우어쎤여뗘벎더떠벋벓떠
ㅇㅇㅇ빠밦탸우처밞밦따빠뚜
ㅇ뇨ㅇ숙어쎤여뗘벎떠벅터벖
ㅇㅇㅇ빠박탸우처밝밤따밣따북
ㅇ됴ㅇ우어썬여텨더벓벓떠뻐더
ㅇㅇㅇ빠받탸우처밣밝다빠따붇
ㅇ뵬ㅇ우어썬여뎌떠벍벓떠뻐터
ㅇㅇㅇ빠밤탸우처밣밝다빠따붇
ㅇ뵬ㅇ우어썬여뎌떠벌벓떠뻐터
ㅇㅇㅇ빠발탸우처밣밝다빠따뿌
ㅇ묘ㅇ우어썬여뎌떠벎더벌벖떠
ㅇㅇㅇ빠밦탸우처밣밝다빠따빠뚜
ㅇ쇽ㅇ우어썬여뎌떠벓더벓떠뻐벖
ㅇㅇㅇ빠밝탸우처밞밞따빠따붒
ㅇ됴ㅇ우어썬여뗘벓더더벍떠뻐
ㅇㅇㅇ빠밣탸우처발발따발따붒
ㅇ뵥ㅇ우어썬여뗘벎더범떠벓떠
ㅇㅇㅇ빠밟탸우처밝발따빠따붏
ㅇ숃어어어쎤여뎌벓떠벎떠범더
ㅇ마샬우싹샥우파뺘무차파쑨
ㅇㅇ오유여어유여ㅇ며ㅇㅇ우
오ㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇ어
우ㅇㅇ어ㅇㅇ어어
샨희맣어

Try it online! (trailing new line for input is necessary)

Why not?

Hours of coding, and another hours of packing and layouting. I think it can be golfed furthermore, but it already took so much effort. I really wanted to pack it into a rectangle.

Because 10^20 is larger than 2^64, not every implementation of Aheui will not support 경-scale numbers.
Luckily, Python and pyaheui implementation (which is used on TIO) uses much-larger precision numbers, so it can support not only 경, but more than 해, 자, 양, 구, 간, 정, 재, 극.
And my code can be easily extended to use more larger unit suffixes.

This code will not terminate on input 0, but this spec was not defined in the question (which should output ).

Explanation-ish Unpacked Code

ㅣPush unit suffixes (만, 억, 조, 경) to stack ㄹ
ㅣ
술
밦발따밝따빠따밦발다우
우ㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
빠따다빠밞빠따받다빠따밝발따다다우
우ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
빠밞받따빠따밦발따타타우
우ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
빠밝빠따밦다빠따밣받따다타우
우ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
ㅣ
ㅣGet input as number
ㅣ
사방우
우ㅡ어
ㅣ
ㅣSplit input by four digits
ㅣ
ㅣㅣIf input is zero, end the loop
아아뺘우차우
우ㅇㅡ어 ㅣ
ㅣㅣ우ㅡㅡ어
ㅣㅣㅣTake mod 10000 to stack ㄲ
ㅣㅣ빠발발다빠따빠따라싺우
ㅣㅣ우ㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
ㅣㅣㅣDivide by 10000
ㅣㅣ발발다빠따빠따나우
ㅣ오ㅡㅡㅡㅡㅡㅡㅡㅡ어
ㅣ
ㅣReverse stack ㄲ to stack ㄱ
ㅣ
샦우싹어
우어
ㅣ
ㅣProcess four digits
ㅣ
아우ㅣUse ㄷ stack for index (0, 2, 4, 6)
ㅣ아삳바우
ㅣ우ㅡㅡ어
ㅣㅣ
ㅣㅣㅣConvert four digits into korean
ㅣ아아숙
ㅣㅣㅣㅣIf current multiplier is zero, escape
ㅣㅣㅣ뺘우차우
ㅣ우ㅇㅡ어 ㅣ
ㅣㅣㅣ우ㅡㅡ어
ㅣㅣㅣㅣTake mod 10
ㅣㅣㅣ빠발발다라우
ㅣㅣㅣ우ㅡㅡㅡㅡ어
ㅣㅣㅣㅣIf remainder - 1 is 0 (remainder is 1) and index is 0 (ones digit), push 일 on stack ㄴ
ㅣㅣㅣ빠받반타탸우처삳뺘우처밝밤따밣따박다빠따밣타싼우
ㅣㅣㅣ우ㅡㅡㅡㅡ어ㅡㅡㅡ어ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
ㅣㅣㅣㅣIf remainder is not 0
ㅣㅣㅣ삭뺘우차우
ㅣㅣㅣ우ㅡ어 ㅣ
ㅣㅣㅣㅣ우ㅡㅡ어
ㅣㅣㅣㅣ숟
ㅣㅣㅣㅣㅣIf index is [2, 4, 6], push [십, 백, 천] on stack ㄴ
ㅣㅣㅣㅣ빠박탸우처발발따빠따밞타밞따밞따발다싼우
ㅣㅣㅣㅣ우ㅡㅡ어ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
ㅣㅣㅣㅣ빠밤탸우처밣빠따밞다빠따밣받따다밞따싼우
ㅣㅣㅣㅣ우ㅡㅡ어ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
ㅣㅣㅣㅣ빠밦탸우처밞밦따빠따밦타박따밞따싼우
ㅣㅣㅣㅣ우ㅡㅡ어ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
ㅣㅣㅣㅣㅣ
ㅣㅣㅣㅣㅣIf remainder is [2 ... 9], push [이 ... 구] on stack ㄴ
ㅣㅣㅣㅣ숙
ㅣㅣㅣㅣ빠박탸우처밝밤따밣따박다빠따밣밣다타싼우
ㅣㅣㅣㅣ우ㅡㅡ어ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
ㅣㅣㅣㅣ빠받탸우처밣밝다빠따받타빠따밣밝따다싼우
ㅣㅣㅣㅣ우ㅡㅡ어ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
ㅣㅣㅣㅣ빠밤탸우처밣밝다빠따받타빠따밣발따다싼우
ㅣㅣㅣㅣ우ㅡㅡ어ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
ㅣㅣㅣㅣ빠발탸우처밣밝다빠따빠따밦발다밞따다싼우
ㅣㅣㅣㅣ우ㅡㅡ어ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
ㅣㅣㅣㅣ빠밦탸우처밣밝다빠따빠따밦빠따밣다밣따다싼우
ㅣㅣㅣㅣ우ㅡㅡ어ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
ㅣㅣㅣㅣ빠밝탸우처밞밞따빠따밦빠따밝다다밣따싼우
ㅣㅣㅣㅣ우ㅡㅡ어ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
ㅣㅣㅣㅣ빠밣탸우처발발따발따밦따밣따밤다밞따싼우
ㅣㅣㅣㅣ우ㅡㅡ어ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
ㅣㅣㅣㅣ빠밟탸우처밝발따빠따밣다밤따밞따밣다싼우
ㅣㅣㅣ우ㅡㅡㅡ어ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
ㅣㅣㅣㅣ
ㅣㅣㅣㅣIncrease index, move onto next digit
ㅣㅣㅣ삳박다삭마발발다나우
ㅣㅣ오ㅡㅡㅡㅡㅡㅡㅡㅡㅡ어
ㅣㅣ
ㅣㅣㅣPop zero
ㅣ아무
ㅣㅣㅣ
ㅣㅣㅣㅣMove one suffix to stack ㄱ
ㅣㅣㅣㅣIf all suffix has been used, escape
ㅣㅣ아샬우싹삭우
ㅣ우ㅇㅡ어  ㅣ
ㅣㅣㅣ우ㅡㅡㅡ어
ㅣㅣㅣㅣIf next multiplier is zero, discard next multiplier and suffix, then check next
ㅣㅣㅣㅣIf next multipler is not zero, move suffix to stack ㄴ and continue
ㅣㅣㅣㅣIf all multiplier has been processed, escape
ㅣㅣㅣ야우파뺘우차파싼우
오ㅇㅇㅡㅇㅡㅡㅇㅡㅡㅡ어
우어ㅇㅡ어ㅡㅡㅣ
ㅣㅡ오ㅡㅡ머머어
샨희맣어
\$\endgroup\$
  • \$\begingroup\$ Are you sure this works for all of the test cases? 10900000014 seems to output 십억구천만일 instead of 백구억십사. \$\endgroup\$ – Kevin Cruijssen Feb 19 '18 at 15:51
  • 1
    \$\begingroup\$ @KevinCruijssen Looks like trailing new line for the input is necessary. \$\endgroup\$ – Casio Feb 19 '18 at 16:14
  • \$\begingroup\$ Ah, that's a weird input-format. But you're right, it indeed works with the new-line in the input. :) +1 from me, nice answer! \$\endgroup\$ – Kevin Cruijssen Feb 19 '18 at 16:18
  • \$\begingroup\$ Wow. Also, you can use any printable ascii character instead of , so this code can be golfed to 1391 bytes instead of 1555. \$\endgroup\$ – 0xrgb Feb 19 '18 at 17:15
  • \$\begingroup\$ @0xrgb Oh, right, right, absolutely. \$\endgroup\$ – Casio Feb 20 '18 at 3:05
4
\$\begingroup\$

Retina 0.8.2, 147 bytes

^
0경0조0억0만
\G0?\D?
0천0백0십$&
+`0(\D)(\d+)(\d)
$2$1$3
0(천0백0십0.?|천|백|십)

1(천|백|십)
$1
T`d`_일이삼사오육칠팔구

Try it online! Link includes test cases. Explanation:

^
0경0조0억0만

Insert the symbols for powers of 10,000.

\G0?\D?
0천0백0십$&

Insert the thousands, hundreds and tens symbols.

+`0(\D)(\d+)(\d)
$2$1$3

Replace the zeros between the symbols with the input digits.

0(천0백0십0.?|천|백|십)

Delete zero thousands, hundreds or tens, or a whole power of 10,000.

1(천|백|십)
$1

Delete the 1 of one thousand, one hundred or one ten.

T`d`_일이삼사오육칠팔구

Transliterate the remaining digits, deleting any remaining zeros.

\$\endgroup\$
  • 1
    \$\begingroup\$ (The bytecount is measured in UTF8. TIO doesn't bother to check all characters are in SBCS) \$\endgroup\$ – user202729 Feb 17 '18 at 15:21
4
\$\begingroup\$

Jelly,  96 95 94  92 bytes

“Ŀ|ĿtĊỴĊḄİ$Ŀ!Ṫ`ạÞḌlĖḣỴ1ṘƈỤṘḢỌṀpḄẒ‘s2ḅ⁹Ọ
bȷ4DUµż“¢½¿€‘ṁ$Ṛœl€1P€0¦ẠÐfFµ€Ṛµ;"“¡ÆÇÐÑ‘ṚL’$ÐfFḟ0ị¢

A monadic link taking a positive integer and returning a list of characters.

Try it online! or see a test-suite (numbers referenced in the OP)
...or see assertion of the pastebin values here

How?

Constructs the parts-characters required as indexes of the list:

[1,2,3,4,5,6,7,8,9,10,100,1000,10000,100000000,1000000000000,10000000000000000]
i.e.: 일이삼사오육칠팔구십백천만억조경

and indexes into the list. Thus 30210 would become [3,13,2,11,10] and then 삼만이백십

“Ŀ|ĿtĊỴĊḄİ$Ŀ!Ṫ`ạÞḌlĖḣỴ1ṘƈỤṘḢỌṀpḄẒ‘s2ḅ⁹Ọ - Link 1, get part-characters: no arguments
“Ŀ|ĿtĊỴĊḄİ$Ŀ!Ṫ`ạÞḌlĖḣỴ1ṘƈỤṘḢỌṀpḄẒ‘      - code-page indices = [199,124,199,116,192,188,192,172,198,36,199,33,206,96,211,20,173,108,194,237,188,49,204,156,185,204,197,181,200,112,172,189]
                                  s2    - split into twos = [[199,124],[199,116],[192,188],[192,172],[198,36],[199,33],[206,96],[211,20],[173,108],[194,237],[188,49],[204,156],[185,204],[197,181],[200,112],[172,189]]
                                    ḅ⁹  - convert from base 256 = [51068,51060,49340,49324,50724,50977,52832,54036,44396,49901,48177,52380,47564,50613,51312,44221]
                                      Ọ - cast to characters = "일이삼사오육칠팔구십백천만억조경"

bȷ4DUµż“¢½¿€‘ṁ$Ṛœl€1P€0¦ẠÐfFµ€Ṛµ;"“¡ÆÇÐÑ‘ṚL’$ÐfFḟ0ị¢ - Main link: integer, n     e.g. 102031
 ȷ4                                                  - 10^4 = 10000
b                                                    - convert (n) to base (10000)    [10,2031]
   D                                                 - convert (each) to base 10      [[1,0],[2,0,3,1]]
    U                                                - reverse each                   [[0,1],[1,3,0,2]]
     µ                      µ€                       - monadic chain for €ach:
              $                                      -   last two links as a monad:
       “¢½¿€‘                                        -     code-page indices = [1,10,11,12]
             ṁ                                       -     mould like             e.g. [1,10] or [1,10,11,12]
      ż                                              -   zip                   [[0,1],[1,10]] or [[1,1],[3,10],[0,11],[2,12]]
               Ṛ                                     -   reverse               [[1,10],[0,1]] or [[2,12],[0,11],[3,10],[1,1]]
                œl€1                                 -   left-strip ones         [[10],[0,1]] or [[2,12],[0,11],[3,10],[]]
                    P€0¦                             -   product @ index 0           [[10],0] or [[2,12],[0,11],[3,10],1]  (Note: the empty product is 1)
                        ẠÐf                          -   filter keep if any            [[10]] or [[2,12],[3,10],1]
                           F                         -   flatten                         [10] or [2,12,3,10,1]
                              Ṛ                      - reverse                        [[2,12,3,10,1],[10]]
                               µ                     - new monadic chain
                                  “¡ÆÇÐÑ‘            - code-page indices = [0,13,14,15,16]
                                ;"                   - zip with concatenation         [[2,12,3,10,1,0],[10,13],14,15,16]
                                         Ṛ           - reverse                        [16,15,14,[10,13],[2,12,3,10,1,0]]
                                             Ðf      - filter keep if:
                                            $        -   last two links as a monad:
                                          L          -     length                      1  1  1   2      6
                                           ’         -     decrement                   0  0  0   1      5
                                                     -                           i.e. [[10,13],[2,12,3,10,1,0]]
                                                     -     (This also removes any 0-sized 10K parts e.g. the [13] from 200001234 -> [16,15,[2,14],[13],[12,2,11,3,10,4,0]])
                                               F     - flatten                        [10,13,2,12,3,10,1,0]
                                                ḟ0   - filter discard zeros           [10,13,2,12,3,10,1]  (Note: not there for multiples of 10000 so cann't simply pop with Ṗ)
                                                   ¢ - call the last link as a nilad  "일이삼사오육칠팔구십백천만억조경"
                                                  ị  - index into                     "십만이천삼십일"
\$\endgroup\$
2
\$\begingroup\$

Ruby, 158 bytes

This task has been haunting me for a few days, but after several iterations of tinkering with the code and gaining max 1-2 bytes at a time, I think it isn't going to become much shorter than this, unless somebody points out a conceptually different approach.

->n{i=0;n.digits.map{|d|'-만억조경'[i%4>0?'':i/4]+'천-십백'[(i+=1)%4]+'0일이삼사오육칠팔구'[d]}.join.reverse.gsub /(0.){4}.|0.|일(?!-)|-/,''}

Try it online!

Explanation

Takes input as integer and extracts the digits (listed from the least to most significant) using the convenient built-in available since Ruby 2.4.

Then, we combine the corresponding Korean digits with position markers and where necessary, 104 block markers. - is a placeholder for the missing markers of lower digits. 천-십백 has such strange ordering because it is rotated by one place to compensate for the fact that we are also incrementing the counter i in the same step.

Finally, we reverse the resulting string back to normal direction and remove some redundant stuff with RegEx replacements:

  • (0.){4}. : 4 * (0+marker) + another marker = a completely empty 104 block.
  • 0. : zeroes at any single position
  • 일(?!-) : ones followed by any meaningful (non-placeholder) markers
  • - : finally, get rid of the placeholders themselves

Alternative

Interestingly, a similar approach, but working with string input is just 1 byte longer:

->s{i=s.size;s.chars.map{|c|'0일이삼사오육칠팔구'[c.to_i]+'-십백천'[(i-=1)%4]+'-만억조경'[i%4>0?'':i/4]}.join.gsub /(0.){4}.|0.|일(?!-)|-/,''}

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Haskell, 270 bytes

(0#_)_=""
(n#1)_=[" 일이삼사오육칠팔구"!!fromInteger n]
(n#b)(c:r)|d<-div n b=[k |d>1,k<-d#1$r]++[c |d>0]++(mod n b#div b 10)r
t=10^4
(n%1)_=f n
(n%b)(c:r)|d<-div n b=[k |d>0,k<-f d++[c]]++(mod n b%div b t)r
f n|n<t=n#1000$"천백십"|1>0=n%(t^4)$"경조억만"

Try it online!

This could probably be improved as there is a bit of duplication but I can't think of a good way of unifying the # and % operators.

Both of those operators work in a similar way but # is for n<10^4 and % is for big numbers. They take the number n, the current "base" b and a list of characters representing the relevant powers of ten in decreasing order. First I divide n by b to get d and stick it's korean representation in front if it's greater than 1 (in the case of numbers less than ten thousand) or 0 (otherwise). Then I insert the representation of the power itself (which should correspond to c) if d>0. Then we just recur by modding n by b and dividing b down to get the base corresponding to the next character.

When we reach n==1 in # We know it's down to a one digit number so we just index into a list (I need fromInteger because Int isn't large enough to store numbers as large as 10^20). When n==1 in % then n is now <10^4 so we recur to # (via f) to do the rest of the number.

\$\endgroup\$
1
\$\begingroup\$

Wolfram Language 23 bytes

Mathematica has a built-in for this. (What a surprise!)

IntegerName[#,"Korean"]&

To save one byte...

#~IntegerName~"Korean"&
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.