[#2] Skript Challenge - Numbers to Words

  • Welcome to skUnity!

    Welcome to skUnity! This is a forum where members of the Skript community can communicate and interact. Skript Resource Creators can post their Resources for all to see and use.

    If you haven't done so already, feel free to join our official Discord server to expand your level of interaction with the comminuty!

    Now, what are you waiting for? Join the community now!

Status
Not open for further replies.

BaeFell

I'm Poppy
Staff member
Admin
skUnity Legend
Nov 27, 2016
1,027
242
73
discord.gg
Discord Username
BaeFell
Hi everyone,

Welcome to another Skript Challenge! I did post a poll on the first Skript Challenge, and the vast majority of users who voted, liked Skript Challenges!
unknown.png

So here's the second one! If you have any suggestions for #3 or general improvements, let me know :emoji_slight_smile:

This Skript Challenge is another number related one! Basically, you must turn numbers into their word versions. Example:
58654 -> 58 thousand, 6 hundred and 54 OR
58654 -> fifty-eight thousand, six hundred and fifty-four
Commas and string formatting isn't important, but extra points for making it pretty

The rules are as follows (note: rules may change between challenge):
- Your code must be in [code]<code>[/code] tags so that I can easily read it.
- You can use addons, but, you're not allowed to use a feature from an addon which does this (don't think any do) and the addon must of been released publicly prior to the creation of this thread. So not, you cannot use a feature like "output {_number} in word form" or whatever.
- You can use another user's code, but please don't edit your messages. I can see all message history and you'll not be counted at all. Remember: this one is about quality, not just length. So trying to cut variable names from someone elses code will lose points!
- WebAPI's or using an external source (outside of Skript), to get your result in not allowed. All submissions must actually do the conversions themselves.

Challenge details (specifics about this challenge):
- Your code must accept any length of number inputted from 0 to 999 million (if you can easily support higher, go for it).
- You do not have to message it back to the player
- It can be a function, command or just a block of code. Just explain where you're getting the input if it's not obvious to me.

How answers will be judged:
Unlike others, the winner for this one, will be judged based on quality. I and others (who I'm yet to pick), will go around and find the best answers. I'm not sure on the specifics of how the scoring will work, the final judgement and most other things, but I've got a week to figure that out!

Important
If you don't understand how your answer will be judged here is an explanation:
Better code quality = more points. I'm very anti-addon with some things. If you're using an addon for what can be done normally in Skript, then you're not Skripting right. Variable names, code structure, use of functions and code readability matters for this challenge. I'm specifically looking for the best code, not the smallest, but you shouldn't have code that is far too long, otherwise it's unlikely to be efficient.

The closing date is 7 days from now -> 16th of February, at 00:06 GMT! Have fun!
 
Last edited:
code_language.skript:
command /num <integer>:
    trigger:
        set {_} to "%arg% tick" parsed as timespan
        set {_} to "%{_}%"
        replace all "seconds" or "second" with "" in {_}
        replace all "minutes" or "minute" with "hundred" in {_}
        replace all "hours" or "hour" with "thousand" in {_}
        broadcast "%{_}%"

code_language.skript:
set {_} to "INPUT tick" parsed as timespan
set {_} to "%{_}%"
replace all "seconds" or "second" with "" in {_}
replace all "minutes" or "minute" with "hundred" in {_}
replace all "hours" or "hour" with "thousand" in {_}
code_language.skript:
set {_} to "INPUT tick" parsed as timespan
set {_} to "%{_}%"
replace all "seconds" or "second" with "" in {_}
replace all "minute" with "hundred" in {_}
replace all "hour" with "thousand" in {_}
 
code_language.skript:
command /num <integer>:
    trigger:
        set {_} to "%arg% tick" parsed as timespan
        set {_} to "%{_}%"
        replace all "seconds" or "second" with "" in {_}
        replace all "minutes" or "minute" with "hundred" in {_}
        replace all "hours" or "hour" with "thousand" in {_}
        broadcast "%{_}%"

code_language.skript:
set {_} to "INPUT tick" parsed as timespan
set {_} to "%{_}%"
replace all "seconds" or "second" with "" in {_}
replace all "minutes" or "minute" with "hundred" in {_}
replace all "hours" or "hour" with "thousand" in {_}
code_language.skript:
set {_} to "INPUT tick" parsed as timespan
set {_} to "%{_}%"
replace all "seconds" or "second" with "" in {_}
replace all "minute" with "hundred" in {_}
replace all "hour" with "thousand" in {_}
I don't think that goes up to 999 million
 
My submission, I will later submit a version that changes 1 to one and 23 to twenty three.
code_language.skript:
function modulo(dividend: integer, divisor: integer) :: number:
  set {_quotient} to {_dividend} / {_divisor}
  set {_floor} to floor({_quotient})
  return {_dividend} - ({_floor} * {_divisor})
function wholeDivision(dividend: integer, divisor: integer) :: number:
  set {_quotient} to {_dividend} / {_divisor}
  set {_floor} to floor({_quotient})
  return {_floor}
function expandedForm(number: integer) :: text:
  #Letter Prefixes so it loops in the correct order
  set {_format::a-quadrillion} to 1000000000000000
  set {_format::b-trillion} to 1000000000000
  set {_format::c-billion} to 1000000000
  set {_format::d-million} to 1000000
  set {_format::e-thousand} to 1000
  set {_format::f-hundred} to 100
  while {_number} is not 0:
    if {_number} < 100:
      #set {_lowerNumberFormats::*} to "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", and "nineteen"
      #set {_tensFormats::*} to "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", and "ninty"
      #if {_number} < 20:
      #  set {_numberFormatted} to {_lowerNumberFormats::%{_number}%}
      #else if {_number} is 100:
      #  set {_numberFormatted} to "one hundred"
      #else:
      #  set {_tensFormatsIndex} to (wholeDivision({_number}, and 10)) - 1
      #  set {_numberFormatted} to {_tensFormats::%{_tensFormatsIndex}%}
      #  if modulo({_number},10) is not 0:
      #    set {_digitNumber} to modulo({_number}, and 10)
      #    set {_digitNumberFormatted} to {_lowerNumberFormats::%{_digitNumber}%}
      #    set {_numberFormatted} to "%{_numberFormatted}% %{_digitNumberFormatted}%"
      #broadcast "ADDED %{_numberFormatted}%"
      set {_numberFormatted} to "%{_number}%"
      add {_numberFormatted} to {_values::*}
      exit loop
    loop {_format::*}:
      set {_place} to loop-value
      #EVALUATE because {_whole} isn't changing after the first time without it
      evaluate "set {_whole} to wholeDivision(%{_number}%, and %{_place}%)"
      if {_whole} > 0:
        if {_place} is 100:
          if {_whole} > 9:
            exit 3 sections
        set {_number} to {_number} - ({_whole} * {_place})
        set {_placeName} to loop-index
        set {_placeName} to subtext of {_placeName} from characters 3 to length of {_placeName}
        if {_whole} is not 0:
          set {_formattedWhole} to {_whole} #Will update later
          add "%{_formattedWhole}% %{_placeName}%" to {_values::*}
  return  "%{_values::*}%"

23 -> 23
gJNVHIs.png
 
code_language.skript:
on load:
  set {large numbers::*} to "thousand", "million", "billion", "trillion", "quadrillion"

function modulus(num: number, by: number) :: number:
  return {_num} - {_by} * rounded down {_num} / {_by}

function smallNumToEnglish(num: number) :: string:
  if {_num} < 100:
    return "%{_num}%"
  else:
    return "%rounded down {_num} / 100% hundred and %modulus({_num}, 100)%"

function numToEnglish(num: number) :: string:
  set {_result} to "%smallNumToEnglish(modulus({_num}, 1000))%"
  set {_num} to rounded down {_num} / 1000
  set {_power of thousand} to 1
  while {_num} > 0:
    set {_number name} to {large numbers::%{_power of thousand}%}
    set {_result} to "%smallNumToEnglish(modulus({_num}, 1000))% %{_number name}%, %{_result}%"
    set {_num} to rounded down {_num} / 1000
    add 1 to {_power of thousand}
  return {_result}
Accepts the input number through the numToEnglish() function.
LCrMdYN.png
 
Numbers to names, featuring recursion.
code_language.skript:
options:
    TABLE: number-to-name
    ERROR: [Error]
  
function define(values: text):
    set {_pairs::*} to {_values} split at " "
 
    loop {_pairs::*}:
        set {_pair::*} to loop-value split at ":"
        set {{@TABLE}::%{_pair::1}%} to {_pair::2}
  
on script load:
    define("1:one 2:two 3:three 4:four 5:five 6:six 7:seven 8:eight 9:nine")
    define("10:ten 11:eleven 12:twelve 13:thirteen 14:fourteen 15:fifteen 16:sixteen 17:seventeen 18:eighteen 19:nineteen")
    define("2.:twenty 3.:thirty 4.:fourty 5.:fifty 6.:sixty 7.:seventy 8.:eighty 9.:ninety")
    define(".__:hundred ...___:thousand ...______:million ..._________:billion ...____________:trillion ..._______________:quadrillion")
 
on script unload:
    delete {{@TABLE}::*}
 
function findMaskFor(number: text) :: text:
    set {_length} to length of {_number}
    set {_digits::*} to {_number} split at ""
 
    loop {{@TABLE}::*}:
 
        if {_skip} is set:
            delete {_skip}
  
        set {_mask} to loop-index
        set {_mask-length} to length of {_mask}
        set {_minimum-length} to {_mask-length}
        set {_chars::*} to {_mask} split at ""
  
        loop {_chars::*}:
      
            {_skip} is not set
      
            set {_char} to loop-value-2
            set {_digit} to {_digits::%loop-index-2%}
                  
            if {_char} is ".":
                set {_minimum-length} to {_minimum-length} - 1
            else:
      
                if {_minimum-length} is greater than {_length}:
                    set {_skip} to true
                else if {_char} is not {_digit} or "_":
                    set {_skip} to true
  
        {_skip} is not set
  
        if {_mask-length} is {_length}:
            return {_mask}
        else if {_length} is less than {_mask-length}:
              
            if {_length} is greater than {_minimum-length}:
                return {_mask}
              
    return "{@ERROR} Unsupported number length: %{_length}%"
 
function startsWith(start-text: text, full-text: text) :: boolean:
    if the first (length of {_start-text}) characters of {_full-text} is {_start-text}:
        return true
    else:
        return false
  
function endsWith(end-text: text, full-text: text) :: boolean:
    if the last (length of {_end-text}) characters of {_full-text} is {_end-text}:
        return true
    else:
        return false
 
function insert(insertion: text, index: number, text: text) :: text:
    set {_left} to the first {_index} characters of {_text}
    set {_right} to the last (length of {_text} - {_index}) characters of {_text}
 
    return "%{_left}%%{_insertion}%%{_right}%"
 
function occurrencesOf(char: text, in: text) :: number:
    set {_count} to 0
    set {_characters::*} to {_in} split at ""
 
    loop {_characters::*}:
 
        if "%loop-value%" is {_char}:
            add 1 to {_count}
      
    return {_count}
 
function stripLeadingZeroes(number: text) :: text:
    while startsWith("0", {_number}):
        if length of {_number} is 1:
            set {_number} to ""
        else:
            set {_number} to the last (length of {_number} - 1) characters of {_number}

    return {_number}
 
function nameOfDigits(number: text) :: text:
    if {_number} is "0":
        return "zero"

    set {_number} to stripLeadingZeroes({_number})
    set {_length} to length of {_number}
 
    if {_length} is 0:
        return ""
 
    set {_mask} to findMaskFor({_number})
  
    if startsWith("{@ERROR}", {_mask}):
        return {_mask}
  
    set {_mask-length} to length of {_mask}
    set {_cut} to {_mask-length} - {_length}
    set {_active-mask} to the last ({_mask-length} - {_cut}) characters of {_mask}
  
    if startsWith(".", {_active-mask}):
        set {_components} to occurrencesOf(".", {_active-mask})
        set {_split-mask::*} to insert(":", {_components}, {_active-mask}) split at ":"
        set {_split-number::*} to insert(":", {_components}, {_number}) split at ":"
  
        set {_left} to nameOfDigits({_split-number::1}) 
        set {_right} to nameOfDigits({_split-number::2}) 
        set {_name} to {{@TABLE}::%{_mask}%}
  
        if {_right} is "zero" or "":
            return "%{_left}% %{_name}%"
        else if {_name} is "hundred":
            return "%{_left}% %{_name}% %{_right}%"
        else:
            return "%{_left}% %{_name}%, %{_right}%"
 
    else if endsWith(".", {_active-mask}):
        set {_left} to {{@TABLE}::%{_mask}%}
        set {_digit} to the last character of {_number}
        set {_right} to nameOfDigits({_digit})
  
        if {_right} is "zero" or "":
            return "%{_left}%"
        else:
            return "%{_left}%-%{_right}%"
  
    else:
        return {{@TABLE}::%{_mask}%}

function nameOfNumber(number: integer) :: text:
    return nameOfDigits("%{_number}%")
  
command /nameof <integer>:
    trigger:
        set {_result} to nameOfNumber(arg-1)
        send "%arg-1%: &a%{_result}%"

Usage:

  • call nameOfDigits() with a string argument
  • or call nameOfNumber() with an integer argument
  • or execute /nameof <integer>

QNmGd4K.png


And since I'm dealing with strings...

...you can expand it to extremely large numbers.
DYnSQnd.png


Just modify the script a little.
Add this to the on script enable event:
code_language.skript:
    define("...__________________:quintillion ..._____________________:sextillion ...________________________:septillion")
    define("...___________________________:octillion ...______________________________:nonillion ..._________________________________:decillion")
    define("...____________________________________:undecillion ..._______________________________________:duodecillion")

And add this anywhere:
code_language.skript:
function validateDigitsOf(text: text) :: boolean:
    set {_chars::*} to {_text} split at ""
 
    loop {_chars::*}:
        if "0123456789" doesn't contain "%loop-value%":
            return false
        
    return true
 
command /nameofdigits <text>:
    trigger:
        if validateDigitsOf(arg-1):
            set {_result} to nameOfDigits(arg-1)
            send "%arg-1%: &a%{_result}%"
        else:
            send "&cThe only characters allowed are: 0-9"
 
Last edited by a moderator:
code_language.skript:
function NumbersToWords(num: number) :: text:
    set {_num} to "%{_num}%"
    length of {_num} <= 2:
        return {_num}
    else if length of {_num} = 3:
        return "%first character of {_num}% hundred and %last 2 characters of {_num}%"
    else if length of {_num} <= 6:
        return "%first (length of {_num} - 3) characters of {_num}% thousand, %subtext of {_num} from (length of {_num} - 2) and (length of {_num} - 2)% hundred and %last 2 characters of {_num}%"
    else if length of {_num} <= 9:
        return "%first (length of {_num} - 6) characters of {_num}% million, %subtext of {_num} from (length of {_num} - 5) and (length of {_num} - 3)% thousand, %subtext of {_num} from (length of {_num} - 2) and (length of {_num} - 2)% hundred and %last 2 characters of {_num}%"

command /test <number>:
    trigger:
        send NumbersToWords(arg)

>> The function is 'NumbersToWords(NumberToTransform)'.
>> No need for addon.

- The code without the function :

code_language.skript:
    set {_num} to "Put your number here."
    length of {_num} <= 2:
        return {_num}
    else if length of {_num} = 3:
        return "%first character of {_num}% hundred and %last 2 characters of {_num}%"
    else if length of {_num} <= 6:
        return "%first (length of {_num} - 3) characters of {_num}% thousand, %subtext of {_num} from (length of {_num} - 2) and (length of {_num} - 2)% hundred and %last 2 characters of {_num}%"
    else if length of {_num} <= 9:
        return "%first (length of {_num} - 6) characters of {_num}% million, %subtext of {_num} from (length of {_num} - 5) and (length of {_num} - 3)% thousand, %subtext of {_num} from (length of {_num} - 2) and (length of {_num} - 2)% hundred and %last 2 characters of {_num}%"

1486637726-2017-02-09-11-54-31.png

Sorry for my bad english, I'm french.
 
Last edited by a moderator:
I think I will win due to my code has less lines as those above my reply (idk whether that's correct grammar, if not sry :3)

code_language.skript:
command /SkriptChallenge:
    trigger:
        send "§oDo you really though that I'm posting here the task? ;)"
        send "§a§oOkay, let's start!"
        shutdown server

EDIT: Due to so many people rated this as "Winner", I should really win, right?
I will just tag @BaeFell, and he could make me win, correct? :emoji_stuck_out_tongue: (Or are we living in America where Trump would "banning" me (from America) - In this case, @BaeFell would delete my WINNER REPLY 'cause he don't have a prizzzeee for meeee :3)
 
Last edited by a moderator:
  • Like
Reactions: Krazy
Made an updated submission, this one is now fully in words, and also removes unnecessary parts (ex. 9000 will translate as nine thousand instead of 9 thousand, 0)

code_language.skript:
on load:
  set {small numbers::*} to "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
  set {multiples of ten::*} to "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"
  set {powers of thousand::*} to "thousand", "million", "billion", "trillion", "quadrillion", "quintillion"

function modulus(num: number, by: number) :: number:
  return {_num} - {_by} * rounded down {_num} / {_by}

function smallNumToEnglish(num: number) :: string:
  if {_num} < 20:
    return {small numbers::%{_num}%}
  if {_num} < 100:
    set {_tens} to rounded down {_num}/10
    set {_result} to {multiples of ten::%{_tens}%}
    if modulus({_num}, 10) > 0:
      set {_result} to "%{_result}%-%smallNumToEnglish(modulus({_num}, 10))%"
    return {_result}
  set {_result} to "%smallNumToEnglish(rounded down {_num}/100)% hundred"
  if modulus({_num}, 100) > 0:
    set {_result} to "%{_result}% and %smallNumToEnglish(modulus({_num}, 100))%"
  return {_result}

function numToEnglish(num: number) :: string:
  if {_num} is 0:
    return "zero"
  set {_power of thousand} to 0
  while {_num} > 0:
    if modulus({_num}, 1000) > 0:
      set {_number name} to {powers of thousand::%{_power of thousand}%}
      set {_result} to "%smallNumToEnglish(modulus({_num}, 1000))% %{_number name}%, %{_result}%"
    set {_num} to rounded down {_num} / 1000
    add 1 to {_power of thousand}
  if {_result} contains ">,":
    return first length of {_result} - 15 characters of {_result} #Removes the extra " <none>, <none>" at the end of the string
  else:
    return first length of {_result} - 8 characters of {_result} #Removes the extra ", <none>" at the end of the string

The image below uses this command to access the function:

code_language.skript:
command /englishnum <number>:
  trigger:
    send "%numToEnglish(arg)%"
164840dfbd8578400218a6ed7c8802f9.png
 
code_language.skript:
function modulo(dividend: integer, divisor: integer) :: number:
  set {_quotient} to {_dividend} / {_divisor}
  set {_floor} to floor({_quotient})
  return {_dividend} - ({_floor} * {_divisor})
code_language.skript:
function modulus(num: number, by: number) :: number:
  return {_num} - {_by} * rounded down {_num} / {_by}
Why not just use the mod(number, number) function of vanilla Skript lol
 
Last edited by a moderator:
code_language.skript:
function NumbersToWords(num: number) :: text:
    set {_num} to "%{_num}%"
    length of {_num} <= 2:
        return {_num}
    else if length of {_num} = 3:
        return "%first character of {_num}% hundred and %last 2 characters of {_num}%"
    else if length of {_num} <= 6:
        return "%first (length of {_num} - 3) characters of {_num}% thousand, %subtext of {_num} from (length of {_num} - 2) and (length of {_num} - 2)% hundred and %last 2 characters of {_num}%"
    else if length of {_num} <= 9:
        return "%first (length of {_num} - 6) characters of {_num}% million, %subtext of {_num} from (length of {_num} - 5) and (length of {_num} - 3)% thousand, %subtext of {_num} from (length of {_num} - 2) and (length of {_num} - 2)% hundred and %last 2 characters of {_num}%"

command /test <number>:
    trigger:
        send NumbersToWords(arg)

>> The function is 'NumbersToWords(NumberToTransform)'.
>> No need for addon.

- The code without the function :

code_language.skript:
    set {_num} to "Put your number here."
    length of {_num} <= 2:
        return {_num}
    else if length of {_num} = 3:
        return "%first character of {_num}% hundred and %last 2 characters of {_num}%"
    else if length of {_num} <= 6:
        return "%first (length of {_num} - 3) characters of {_num}% thousand, %subtext of {_num} from (length of {_num} - 2) and (length of {_num} - 2)% hundred and %last 2 characters of {_num}%"
    else if length of {_num} <= 9:
        return "%first (length of {_num} - 6) characters of {_num}% million, %subtext of {_num} from (length of {_num} - 5) and (length of {_num} - 3)% thousand, %subtext of {_num} from (length of {_num} - 2) and (length of {_num} - 2)% hundred and %last 2 characters of {_num}%"

1486637726-2017-02-09-11-54-31.png

Sorry for my bad english, I'm french.
Ha bah on est pas les seuls :emoji_wink:
 
Updating mine to improve readability. It also now runs on pure Skript 2.2 (it was using some SkQuery syntax features before).

code_language.skript:
options:
    TABLE: number-to-name
    ERROR: [Error]
    ENABLE_LARGE_NUMBER_NAMES: true

# Define all masks in a string with pattern:name pairs.

function defineMasksIn(values: text):

    set {_pairs::*} to {_values} split at " "
   
    loop {_pairs::*}:
   
        set {_pair::*} to loop-value split at ":"
        set {{@TABLE}::%{_pair::1}%} to {_pair::2}
       
on script load:

    defineMasksIn("1:one 2:two 3:three 4:four 5:five 6:six 7:seven 8:eight 9:nine")
    defineMasksIn("10:ten 11:eleven 12:twelve 13:thirteen 14:fourteen 15:fifteen 16:sixteen 17:seventeen 18:eighteen 19:nineteen")
    defineMasksIn("2.:twenty 3.:thirty 4.:forty 5.:fifty 6.:sixty 7.:seventy 8.:eighty 9.:ninety")
    defineMasksIn(".__:hundred ...___:thousand ...______:million ..._________:billion ...____________:trillion ..._______________:quadrillion")
   
    {@ENABLE_LARGE_NUMBER_NAMES} is true
   
    # Number names from: https://en.wikipedia.org/wiki/Names_of_large_numbers
   
    defineMasksIn("...__________________:quintillion ..._____________________:sextillion ...________________________:septillion")
    defineMasksIn("...___________________________:octillion ...______________________________:nonillion ..._________________________________:decillion")
   
    defineMasksIn("...____________________________________:undecillion ..._______________________________________:duodecillion")
    defineMasksIn("...__________________________________________:tredecillion ..._____________________________________________:quattuordecillion")
    defineMasksIn("...________________________________________________:quindecillion ...___________________________________________________:sexdecillion")
   
on script unload:

    delete {{@TABLE}::*}
   
# Returns the matching mask for a string of digits or an error if nothing is found.
   
function findMaskFor(number: text) :: text:

    set {_length} to length of {_number}
    set {_digits::*} to {_number} split at ""
   
    loop {{@TABLE}::*}:
   
        if {_skip} is set:
       
            delete {_skip}
       
        set {_mask} to loop-index
        set {_mask-length} to length of {_mask}
        set {_minimum-length} to {_mask-length}
        set {_chars::*} to {_mask} split at ""
       
        loop {_chars::*}:
           
            {_skip} is not set
           
            set {_char} to loop-value-2
            set {_digit} to {_digits::%loop-index-2%}
                       
            if {_char} is ".":
           
                set {_minimum-length} to {_minimum-length} - 1
               
            else:
           
                if {_minimum-length} is greater than {_length}:
               
                    set {_skip} to true
                   
                else if {_char} is not {_digit} or "_":
               
                    set {_skip} to true
       
        {_skip} is not set
       
        if {_mask-length} is {_length}:
       
            return {_mask}
           
        else if {_length} is less than {_mask-length}:
           
            if {_length} is greater than {_minimum-length}:
           
                return {_mask}
           
    return "{@ERROR} Unsupported value: '%{_number}%' with length %{_length}%"

# Determine whether a string starts with another.

function startsWith(start-text: text, full-text: text) :: boolean:

    if the first (length of {_start-text}) characters of {_full-text} is {_start-text}:
        return true
    return false

# Determine whether a string ends with another.

function endsWith(end-text: text, full-text: text) :: boolean:

    if the last (length of {_end-text}) characters of {_full-text} is {_end-text}:
        return true
    return false

# Insert a string into another at a specified index.

function insert(insertion: text, index: number, text: text) :: text:

    set {_left} to the first {_index} characters of {_text}
    set {_right} to the last (length of {_text} - {_index}) characters of {_text}
   
    return "%{_left}%%{_insertion}%%{_right}%"
   
# Count the occurrences of a character in a string.
   
function occurrencesOf(char: text, in: text) :: number:

    set {_count} to 0
    set {_characters::*} to {_in} split at ""
   
    loop {_characters::*}:
   
        if "%loop-value%" is {_char}:
       
            add 1 to {_count}
           
    return {_count}
   
# Strip all leading zeroes from a string of digits.
   
function stripLeadingZeroes(number: text) :: text:

    while startsWith("0", {_number}) is true:
   
        if length of {_number} is 1:
            set {_number} to ""
        else:
            set {_number} to the last (length of {_number} - 1) characters of {_number}

    return {_number}
   
# Returns the full name of all digits in a string.
   
function nameOfDigits(number: text) :: text:

    if {_number} is "0":
   
        return "zero"

    set {_number} to stripLeadingZeroes({_number})
    set {_length} to length of {_number}
   
    if {_length} is 0:
   
        return ""
   
    set {_mask} to findMaskFor({_number})
       
    if startsWith("{@ERROR}", {_mask}) is true:
   
        return {_mask}
       
    set {_mask-length} to length of {_mask}
    set {_mask-cutoff} to {_mask-length} - {_length}
    set {_active-mask} to the last ({_mask-length} - {_mask-cutoff}) characters of {_mask}
       
    if startsWith(".", {_active-mask}) is true:
   
        set {_left-side-components} to occurrencesOf(".", {_active-mask})
        set {_split-number::*} to insert(":", {_left-side-components}, {_number}) split at ":"
       
        set {_left} to nameOfDigits({_split-number::1})      
        set {_right} to nameOfDigits({_split-number::2})      
        set {_name} to {{@TABLE}::%{_mask}%}
       
        if {_right} is "zero" or "":
            return "%{_left}% %{_name}%"
        else if {_name} is "hundred":
            return "%{_left}% %{_name}% %{_right}%"
        else:
            return "%{_left}% %{_name}%, %{_right}%"
   
    else if endsWith(".", {_active-mask}) is true:
   
        set {_left} to {{@TABLE}::%{_mask}%}
        set {_digit} to the last character of {_number}
        set {_right} to nameOfDigits({_digit})
       
        if {_right} is "zero" or "":
            return "%{_left}%"
        else:
            return "%{_left}%-%{_right}%"
       
    else:
   
        return {{@TABLE}::%{_mask}%}
       
# Converts an integer to a string and returns the result of nameOfDigits()

function nameOfNumber(number: integer) :: text:

    return nameOfDigits("%{_number}%")

command /nameof <integer>:
    trigger:
   
        set {_result} to nameOfNumber(arg-1)
        send "%arg-1%: &a%{_result}%"
       
# A function to ensure a string only contains numeric characters.

function validateDigitsOf(text: text) :: boolean:

    set {_chars::*} to {_text} split at ""
   
    loop {_chars::*}:
        if "0123456789" doesn't contain "%loop-value%":
            return false
           
    return true
   
command /nameofdigits <text>:
    trigger:
   
        if validateDigitsOf(arg-1) is true:
       
            set {_result} to nameOfDigits(arg-1)
            send "%arg-1%: &a%{_result}%"
           
        else:
       
            send "&cThe only characters allowed are: 0-9"

Usage:
  • call nameOfDigits() with a string argument
  • or call nameOfNumber() with an integer argument
  • or execute /nameof <integer>
  • or execute /nameofdigits <text>
6hUpPaX.png
 
Last edited by a moderator:
Updating mine to improve readability. It also now runs on pure Skript 2.2 (it was using some SkQuery syntax features before).

code_language.skript:
options:
    TABLE: number-to-name
    ERROR: [Error]
    ENABLE_LARGE_NUMBER_NAMES: true

# Define all masks in a string with pattern:name pairs.

function defineMasksIn(values: text):

    set {_pairs::*} to {_values} split at " "
 
    loop {_pairs::*}:
 
        set {_pair::*} to loop-value split at ":"
        set {{@TABLE}::%{_pair::1}%} to {_pair::2}
    
on script load:

    defineMasksIn("1:one 2:two 3:three 4:four 5:five 6:six 7:seven 8:eight 9:nine")
    defineMasksIn("10:ten 11:eleven 12:twelve 13:thirteen 14:fourteen 15:fifteen 16:sixteen 17:seventeen 18:eighteen 19:nineteen")
    defineMasksIn("2.:twenty 3.:thirty 4.:forty 5.:fifty 6.:sixty 7.:seventy 8.:eighty 9.:ninety")
    defineMasksIn(".__:hundred ...___:thousand ...______:million ..._________:billion ...____________:trillion ..._______________:quadrillion")
 
    {@ENABLE_LARGE_NUMBER_NAMES} is true
 
    # Number names from: https://en.wikipedia.org/wiki/Names_of_large_numbers
 
    defineMasksIn("...__________________:quintillion ..._____________________:sextillion ...________________________:septillion")
    defineMasksIn("...___________________________:octillion ...______________________________:nonillion ..._________________________________:decillion")
 
    defineMasksIn("...____________________________________:undecillion ..._______________________________________:duodecillion")
    defineMasksIn("...__________________________________________:tredecillion ..._____________________________________________:quattuordecillion")
    defineMasksIn("...________________________________________________:quindecillion ...___________________________________________________:sexdecillion")
 
on script unload:

    delete {{@TABLE}::*}
 
# Returns the matching mask for a string of digits or an error if nothing is found.
 
function findMaskFor(number: text) :: text:

    set {_length} to length of {_number}
    set {_digits::*} to {_number} split at ""
 
    loop {{@TABLE}::*}:
 
        if {_skip} is set:
    
            delete {_skip}
    
        set {_mask} to loop-index
        set {_mask-length} to length of {_mask}
        set {_minimum-length} to {_mask-length}
        set {_chars::*} to {_mask} split at ""
    
        loop {_chars::*}:
        
            {_skip} is not set
        
            set {_char} to loop-value-2
            set {_digit} to {_digits::%loop-index-2%}
                    
            if {_char} is ".":
        
                set {_minimum-length} to {_minimum-length} - 1
            
            else:
        
                if {_minimum-length} is greater than {_length}:
            
                    set {_skip} to true
                
                else if {_char} is not {_digit} or "_":
            
                    set {_skip} to true
    
        {_skip} is not set
    
        if {_mask-length} is {_length}:
    
            return {_mask}
        
        else if {_length} is less than {_mask-length}:
        
            if {_length} is greater than {_minimum-length}:
        
                return {_mask}
        
    return "{@ERROR} Unsupported value: '%{_number}%' with length %{_length}%"

# Determine whether a string starts with another.

function startsWith(start-text: text, full-text: text) :: boolean:

    if the first (length of {_start-text}) characters of {_full-text} is {_start-text}:
        return true
    return false

# Determine whether a string ends with another.

function endsWith(end-text: text, full-text: text) :: boolean:

    if the last (length of {_end-text}) characters of {_full-text} is {_end-text}:
        return true
    return false

# Insert a string into another at a specified index.

function insert(insertion: text, index: number, text: text) :: text:

    set {_left} to the first {_index} characters of {_text}
    set {_right} to the last (length of {_text} - {_index}) characters of {_text}
 
    return "%{_left}%%{_insertion}%%{_right}%"
 
# Count the occurrences of a character in a string.
 
function occurrencesOf(char: text, in: text) :: number:

    set {_count} to 0
    set {_characters::*} to {_in} split at ""
 
    loop {_characters::*}:
 
        if "%loop-value%" is {_char}:
    
            add 1 to {_count}
        
    return {_count}
 
# Strip all leading zeroes from a string of digits.
 
function stripLeadingZeroes(number: text) :: text:

    while startsWith("0", {_number}) is true:
 
        if length of {_number} is 1:
            set {_number} to ""
        else:
            set {_number} to the last (length of {_number} - 1) characters of {_number}

    return {_number}
 
# Returns the full name of all digits in a string.
 
function nameOfDigits(number: text) :: text:

    if {_number} is "0":
 
        return "zero"

    set {_number} to stripLeadingZeroes({_number})
    set {_length} to length of {_number}
 
    if {_length} is 0:
 
        return ""
 
    set {_mask} to findMaskFor({_number})
    
    if startsWith("{@ERROR}", {_mask}) is true:
 
        return {_mask}
    
    set {_mask-length} to length of {_mask}
    set {_mask-cutoff} to {_mask-length} - {_length}
    set {_active-mask} to the last ({_mask-length} - {_mask-cutoff}) characters of {_mask}
    
    if startsWith(".", {_active-mask}) is true:
 
        set {_left-side-components} to occurrencesOf(".", {_active-mask})
        set {_split-number::*} to insert(":", {_left-side-components}, {_number}) split at ":"
    
        set {_left} to nameOfDigits({_split-number::1})   
        set {_right} to nameOfDigits({_split-number::2})   
        set {_name} to {{@TABLE}::%{_mask}%}
    
        if {_right} is "zero" or "":
            return "%{_left}% %{_name}%"
        else if {_name} is "hundred":
            return "%{_left}% %{_name}% %{_right}%"
        else:
            return "%{_left}% %{_name}%, %{_right}%"
 
    else if endsWith(".", {_active-mask}) is true:
 
        set {_left} to {{@TABLE}::%{_mask}%}
        set {_digit} to the last character of {_number}
        set {_right} to nameOfDigits({_digit})
    
        if {_right} is "zero" or "":
            return "%{_left}%"
        else:
            return "%{_left}%-%{_right}%"
    
    else:
 
        return {{@TABLE}::%{_mask}%}
    
# Converts an integer to a string and returns the result of nameOfDigits()

function nameOfNumber(number: integer) :: text:

    return nameOfDigits("%{_number}%")

command /nameof <integer>:
    trigger:
 
        set {_result} to nameOfNumber(arg-1)
        send "%arg-1%: &a%{_result}%"
    
# A function to ensure a string only contains numeric characters.

function validateDigitsOf(text: text) :: boolean:

    set {_chars::*} to {_text} split at ""
 
    loop {_chars::*}:
        if "0123456789" doesn't contain "%loop-value%":
            return false
        
    return true
 
command /nameofdigits <text>:
    trigger:
 
        if validateDigitsOf(arg-1) is true:
    
            set {_result} to nameOfDigits(arg-1)
            send "%arg-1%: &a%{_result}%"
        
        else:
    
            send "&cThe only characters allowed are: 0-9"

Usage:
  • call nameOfDigits() with a string argument
  • or call nameOfNumber() with an integer argument
  • or execute /nameof <integer>
  • or execute /nameofdigits <text>
6hUpPaX.png

When you realize that this is one hundred twenty-three sexdecillion times better than anything you could ever make:

 
Status
Not open for further replies.