# Objective

Given a positive integer, spell it out in the conlang I made.

# Specification

Let $$\n\$$ be the inputted integer. $$\n\$$ shall be spelled out in the following specification. The entire spelling is case sensitive.

With the decimal expansion of $$\n\$$, let d be the least significant nonzero digit of $$\n\$$.

First, d shall be spelled out like this:

• 1 = Qun

• 2 = Pis

• 3 = Tel

• 4 = Kal

• 5 = Pan

• 6 = Soh

• 7 = Set

• 8 = Qok

• 9 = Nof

Second, an appropriate suffix (or a "particle" in linguistic sense?) will immediately follow. This is judged by two boolean conditions: (A) Whether d has any trailing zeros, and (B) whether d is not the only nonzero digit.

• If neither holds, the suffix shall be em.

• If only (A) holds, the suffix shall be eh.

• If only (B) holds, the suffix shall be at.

• If both hold, the suffix shall be om.

Third, if (A) held, the length of the trailing zeros shall be spelled out recursively.

Finally, if (B) held, d and the trailing zeros shall be stripped off, and the remaining digits shall be spelled out recursively.

All words shall be intercalated by a single ASCII 0x20 whitespace.

# Examples

• 1 = Qunem

• 2 = Pisem

• 7 = Setem

• 10 = Quneh Qunem

• 11 = Qunat Qunem

• 12 = Pisat Qunem

• 19 = Nofat Qunem

• 20 = Piseh Qunem

• 42 = Pisat Kalem

• 69 = Nofat Sohem

• 100 = Quneh Pisem

• 109 = Nofat Quneh Qunem

• 440 = Kalom Qunem Kalem

• 666 = Sohat Sohat Sohem

• 1945 = Panat Kalat Nofat Qunem

• 2000 = Piseh Telem

• 2022 = Pisat Pisat Piseh Qunem

• 44100 = Qunom Pisem Kalat Kalem

• 144000 = Kalom Telem Kalat Qunem

• $$\10^{60}\$$ = Quneh Soheh Qunem

• $$\10^{63}\$$ = Quneh Telat Sohem

# Rules

I/O format is flexible. Standard loopholes apply.

As for input, those that are not positive integers fall in don't care situation.

As for output, trailing whitespaces are permitted, but leading whitespaces are not.

# Ungolfed solution

import Data.List
import Numeric.Natural

spellNDos :: Natural -> String
spellNDos 0 = ""
spellNDos n = go (reverse (show n)) where
go "" = ""
go str = let
(zeros, digit:remaining) = partition ('0'==) str
digitSpell = case digit of
'1' -> "Qun"
'2' -> "Pis"
'3' -> "Tel"
'4' -> "Kal"
'5' -> "Pan"
'6' -> "Soh"
'7' -> "Set"
'8' -> "Qok"
_   -> "Nof"
suffix = case (null zeros, null remaining) of
(False, False) -> "om "
(False, _    ) -> "eh "
(_    , False) -> "at "
_              -> "em "
in digitSpell ++ suffix ++ spellNDos (genericLength zeros) ++ go remaining

• "d is not the only nonzero digit." This is a bit unclear to me, can someone explain what it means?
– oeuf
Apr 25 at 13:59
• @oeuf Because zeroes don't have their own word, and so only 1-9 count as "digits" - if a number is x00 or x00000 then it is the only nonzero digit (= the last digit), if it's xyz or x0yz0 or y00z, z is the last, x, y are not the last Apr 26 at 2:52

# Python 3.8 (pre-release), 172 bytes

f=lambda n:(d:=n.strip('0'))and' QPTKPSSQNuieaaoeoonsllnhtkf'[int(l:=d[-1])::9]+'eeaomhtm'[(t:=n!=d)+1%len(d)*2::4]+(' '+f(str(N:=n[::-1].find(l))).strip())*t+' '+f(n[:~N])


Try it online!

Straightforward implementation of the specification.

Input a string. Makes use of string indexing and various other tricks to simplify finding the least significant digit and removing digits. This makes the task much easier to accomplish because with numbers, one would have to perform messy tasks such as dividing by powers of 10 or using the % operator to "index into the number", and because of this difficulty it is golfier to convert the number to a string then perform some indexing. Then I thought, "Why not just use a string for the input?" and the code was thus shortened by 25 bytes, maybe more.

Thanks @ovs for -2 bytes.

# Charcoal, 86 bytes

⊞υＮＷυ«≔⊟υι¿ι«≔⌕⮌÷¹⊕↨ιχ⁰θ≧÷Ｘχθι§⪪”↶0ＯＰ⊘ηS℅ê*k⮌⁰nI¿'⊗ξ!»NV”³ι≧÷χι⊞υι⊞υθ¿θ¿ιom¦eh¿ιat¦em→


Try it online! Link is to verbose version of code. Explanation:

⊞υＮＷυ«


Start processing with the input value.

≔⊟υι¿ι«


If the current value to process is zero then ignore it and continue on to the next value.

≔⌕⮌÷¹⊕↨ιχ⁰θ≧÷Ｘχθι


Find the number of trailing zeros in the current value and remove them.

§⪪”↶0ＯＰ⊘ηS℅ê*k⮌⁰nI¿'⊗ξ!»NV”³ι


Output the prefix corresponding to the last nonzero digit.

≧÷χι


Divide the value by 10 again.

⊞υι⊞υθ


Push the final value and the number of trailing zeros to the list so that they get processed.

¿θ¿ιom¦eh¿ιat¦em→


Output the appropriate suffix and allow a space before any other output.

# 05AB1E, 72 bytes

"SDĀÅ¡¦ηRεDg≠UθćsgV.•¿Õ¾¸”mÚÄú±pE”¿м∍•3ôsè™.•DĀ€y‹•2ôYĀX«Cè«Y®.V‚"©.V˜ðý


Explanation:

"..."           # Push the recursive string explained below
©          # Store it in variable ® (without popping)
.V        # Execute it as 05AB1E code
˜       # Flatten the resulting list
ðý     # Join this list with space delimiter)
# (after which the result is output implicitly)

S               # Convert the current value to a list of digits
# (which will be the implicit input in the first iteration)
D              # Duplicate this list of digits
Ā             # Check for each digit if it's non-0
Å¡           # Split the list of digits at the truthy (non-0) indices
¦          # Remove the leading empty list
#  (e.g. "20230050" → [[2,0],[2],[3,0,0],[5,0]])
η               # Get the prefixes of this list
R              # Reverse it
ε             # Map over each prefix-list:
D            #  Duplicate the current list of lists
g           #  Pop the copy, and push its length
≠          #  Check that this length is NOT 1
U         #  Pop and store this in variable X
θ           #  Pop and push the final digit-list from the current prefix
ć          #  Extract head; pop and push first item and remainder-list
#  separately
s         #  Swap so the remainder-list of 0s is at the top
g        #  Pop and push its length (to get the amount of 0s)
V       #  Pop and store this in variable Y
.•¿Õ¾¸”mÚÄú±pE”¿м∍•
#  Push compressed string "nofqunpistelkalpansohsetqok"
3ô      #  Split it into parts of size 3
s     #  Swap so the extracted head is at the top
è    #  (Modular 0-based) index it into the list of triplets
™   #  Titlecase it
.•DĀ€y‹•    #  Push compressed string "ematehom"
2ô        #  Split it into parts of size 2
YĀ      #  Push Y (amount of 0s), and check if it's NOT 0
X«    #  Append X (prefix_length != 1)
C   #  Convert it from binary to an integer
#  (0 if X=0,Y=0; 1 if X=0,Y=1, 2 if X=1,Y=0, 3 if X=1,Y=1)
è  #  Index that into the list of pairs
« #  Append the two strings together
Y           #  Push Y (amount of 0s) again
®.V        #  Do a recursive call with this as argument
‚       #  Pair the result together with the string


See this 05AB1E tip of mine (section How to compress strings not part of the dictionary?) to understand why .•¿Õ¾¸”mÚÄú±pE”¿м∍• is "nofqunpistelkalpansohsetqok" and .•DĀ€y‹• is "ematehom".

# JavaScript (ES6),  148 145  144 bytes

Expects the input integer as a string.

f=s=>x=s.replace(/[^0]0*/g,q=>s=b[+q[0]+3]+b[!s+2*!f(q.length-1+'')]+' '+x+s,s="",b="omehatemQunPisTelKalPanSohSetQokNof".match(/[A-Z]?../g))&&s


Try it online!

### How?

We first extract all suffixes and prefixes from the string "omehatemQunPis...Nof" into the array b[], using the regular expression /[A-Z]?../g.

f =              // f is a recursive function taking
s =>             // a string s
x =              // the final result is saved in x
s.replace(       // look for all digit groups consisting of
/[^0]0*/g,     // a non-zero digit followed by 0 to N zeros
q =>           // for each such group q:
s =          //   update s:
b[           //     append the prefix according to
+q[0] + 3  //     the leading non-zero digit
] +          //
b[           //     append the suffix according to
!s +       //     whether this is the leading group
2 * !f(    //     and whether there's at least one zero,
q.length //     which is deduced from the result of a
- 1      //     recursive call with the number of 0's
+ ''     //     coerced to a string
)          //
] +          //     append:
' ' +        //       - a space
x +          //       - the result of the recursive call
s,           //       - the previous value of s
)                // end of replace()
&& s             // return s


# Jelly, 71 bytes

DœṗḊĖF€ṚµḢỊ;ȦḄị“ðỌÇƭḌ€h»s2¤ṭḢị“÷mƬ@wƇ75Ẉ⁸f0¦mḃ⁾æÑdṛƁ/.ⱮṾ»s3¤Ɗ,Lß$K⁸¡)K  A full program that accepts a positive integer and prints the result Try it online! Or see the test-suite. ### How? DœṗḊĖF€ṚµḢỊ;ȦḄị“...»s2¤ṭḢị“...»s3¤Ɗ,Lß$K⁸¡)K - Main Link: positive integer, N
D                                             - decimal digits of N
                                          - use as both arguments of:
œṗ                                           -   partition before truthy indices
Ḋ                                         - dequeue (remove leading empty list)
Ė                                        - enumerate (e.g. [a,b,c]->[[1,a],[2,a],[3,c]])
F€                                      - flatten each
Ṛ                                     - reverse
µ                                 )  - for each "Part":
Ḣ                                   -   head (i.e. the original index) - Note: this removes it too
Ị                                  -   is insignificant (i.e. are we dealing with the final d? = NOT B)
Ȧ                                -   any and all? (0 if any zeros else 1 = NOT A)
;                                 -   concatenate -> [NOT B, NOT A]
Ḅ                               -   from binary -> 2(NOT B)+(NOT A)
“...»                         -     "atehemom"
s2                       -     split into twos -> ["at","eh","em","om"]
ị                              -   index into -> appropriate suffix
Ḣ                    -     head -> d - Note: again, this removes it too
“...»              -       "QunPisTelKalPanSohSetQokNof"
s3            -       split into threes -> ["Qun","Pis","Tel","Kal","Pan","Soh","Set","Qok","Nof"]
ị                   -     index into -> appropriate prefix
ṭ                     -   tack -> [prefix,suffix]
`