This is a working conversion of Nick Gammon's number conversion scripts.
-- Convert a number to words
-- Author: Nick Gammon
-- Date: 18th March 2010
-- Examples of use:
-- words = convert_numbers_to_words ("94921277802687490518")
-- number = convert_words_to_numbers ("one hundred eight thousand three hundred nine")
-- Both functions return nil and an error message so you can check for failure,
-- or assert, eg. words = assert (convert_numbers_to_words ("2687490518"))
-- Units, must be in inverse order!
-- The trailing space is required as the space between words
local inverse_units = {
"vigintillion ", -- 10^63
"novemdecillion ", -- 10^60
"octodecillion ", -- 10^57
"septendecillion ", -- 10^54
"sexdecillion ", -- 10^51
"quindecillion ", -- 10^48
"quattuordecillion ",-- 10^45
"tredecillion ", -- 10^42
"duodecillion ", -- 10^39
"undecillion ", -- 10^36
"decillion ", -- 10^33
"nonillion ", -- 10^30
"octillion ", -- 10^27
"septillion ", -- 10^24
"sextillion ", -- 10^21
"quintillion ", -- 10^18
"quadrillion ", -- 10^15
"trillion ", -- 10^12
"billion ", -- 10^9
"million ", -- 10^6
"thousand ", -- 10^3
} -- inverse_units
local inverse_numbers = {
"one ",
"two ",
"three ",
"four ",
"five ",
"six ",
"seven ",
"eight ",
"nine ",
"ten ",
"eleven ",
"twelve ",
"thirteen ",
"fourteen ",
"fifteen ",
"sixteen ",
"seventeen ",
"eighteen ",
"nineteen ",
"twenty ",
[30] = "thirty ",
[40] = "forty ",
[50] = "fifty ",
[60] = "sixty ",
[70] = "seventy ",
[80] = "eighty ",
[90] = "ninety ",
} -- inverse_numbers
local function convert_up_to_999 (n)
if n <= 0 then
return ""
end -- if zero
local hundreds = math.floor (n / 100)
local tens = math.floor (n % 100)
local result = ""
-- if over 99 we need to say x hundred
if hundreds > 0 then
result = inverse_numbers [hundreds] .. "hundred "
if tens == 0 then
return result
end -- if only a digit in the hundreds column
-- to have "and" between things like "hundred and ten"
-- uncomment the next line
-- result = result .. "and "
end -- if
-- up to twenty it is then just five hundred (and) fifteen
if tens <= 20 then
return result .. inverse_numbers [tens]
end -- if
-- otherwise we need: thirty (something)
result = result .. inverse_numbers [math.floor (tens / 10) * 10]
-- get final digit (eg. thirty four)
local digits = math.floor (n % 10)
-- to put a hyphen between things like "forty-two"
-- uncomment the WITH HYPHEN line and
-- comment out the NO HYPHEN line
if digits > 0 then
result = result .. inverse_numbers [digits] -- NO HYPHEN
-- result = string.sub (result, 1, -2) .. "-" .. inverse_numbers [digits] -- WITH HYPHEN
end -- if
return result
end -- convert_up_to_999
-- convert a number to words
-- See: http://www.gammon.com.au/forum/?id=10155
function convert_numbers_to_words (n)
local s = tostring (n)
-- preliminary sanity checks
local c = string.match (s, "%D")
if c then
return nil, "Non-numeric digit '" .. c .. "' in number"
end -- if
if #s == 0 then
return nil, "No number supplied"
elseif #s > 66 then
return nil, "Number too big to convert to words"
end -- if
-- make multiple of 3
while #s % 3 > 0 do
s = "0" .. s
end -- while
local result = ""
local start = #inverse_units - (#s / 3) + 2
for i = start, #inverse_units do
local group = tonumber (string.sub (s, 1, 3))
if group > 0 then
result = result .. convert_up_to_999 (group) .. inverse_units [i]
end -- if not zero
s = string.sub (s, 4)
end -- for
result = result .. convert_up_to_999 (tonumber (s))
if result == "" then
result = "zero"
end -- if
return (string.gsub (result, " +$", "")) -- trim trailing spaces
end -- convert_numbers_to_words
-- Convert words to a number
-- Author: Nick Gammon
-- Date: 18th March 2010
-- Does NOT handle decimal places (eg. four point six)
local numbers = {
zero = 0,
one = 1,
two = 2,
three = 3,
four = 4,
five = 5,
six = 6,
seven = 7,
eight = 8,
nine = 9,
ten = 10,
eleven = 11,
twelve = 12,
thirteen = 13,
fourteen = 14,
fifteen = 15,
sixteen = 16,
seventeen = 17,
eighteen = 18,
nineteen = 19,
twenty = 20,
thirty = 30,
forty = 40,
fifty = 50,
sixty = 60,
seventy = 70,
eighty = 80,
ninety = 90,
} -- numbers
local units = {
hundred = ("100"),
thousand = ("1" .. string.rep ("0", 3)),
million = ("1" .. string.rep ("0", 6)),
billion = ("1" .. string.rep ("0", 9)),
trillion = ("1" .. string.rep ("0", 12)),
quadrillion = ("1" .. string.rep ("0", 15)),
quintillion = ("1" .. string.rep ("0", 18)),
sextillion = ("1" .. string.rep ("0", 21)),
septillion = ("1" .. string.rep ("0", 24)),
octillion = ("1" .. string.rep ("0", 27)),
nonillion = ("1" .. string.rep ("0", 30)),
decillion = ("1" .. string.rep ("0", 33)),
undecillion = ("1" .. string.rep ("0", 36)),
duodecillion = ("1" .. string.rep ("0", 39)),
tredecillion = ("1" .. string.rep ("0", 42)),
quattuordecillion = ("1" .. string.rep ("0", 45)),
quindecillion = ("1" .. string.rep ("0", 48)),
sexdecillion = ("1" .. string.rep ("0", 51)),
septendecillion = ("1" .. string.rep ("0", 54)),
octodecillion = ("1" .. string.rep ("0", 57)),
novemdecillion = ("1" .. string.rep ("0", 60)),
vigintillion = ("1" .. string.rep ("0", 63)),
} -- units
-- convert a number in words to a numeric form
-- See: http://www.gammon.com.au/forum/?id=10155
-- Thanks to David Haley
function convert_words_to_numbers (s)
local stack = {}
local previous_type
for word in string.gmatch (s:lower (), "[%a%d]+") do
if word ~= "and" then -- skip "and" (like "hundred and fifty two")
local top = #stack
-- If the current word is a number (English or numeric),
-- and the previous word was also a number, pop the previous number
-- from the stack and push the addition of the two numbers.
-- Otherwise, push the new number.
local number = tonumber (word) -- try for numeric (eg. 22 thousand)
if number then
number = (number) -- turn into "big number"
else
number = numbers [word]
end -- if a number-word "like: twenty"
if number then
if previous_type == "number" then -- eg. forty three
local previous_number = table.remove (stack, top) -- get the forty
number = number + previous_number -- add three
end -- if
table.insert (stack, number)
previous_type = "number"
else
-- If the current word is a unit, multiply the number on the top of the stack by the unit's magnitude.
local unit = units [word]
if not unit then
return nil, "Unexpected word: " .. word
end -- not unit
previous_type = "unit"
-- It is an error to get a unit before a number.
if top == 0 then
return nil, "Cannot have unit before a number: " .. word
end -- starts of with something like "thousand"
-- pop until we get something larger on the stack
local interim_result = (0)
while top > 0 and stack [top] < unit do
interim_result = interim_result + table.remove (stack, top)
top = #stack
end -- while
table.insert (stack, interim_result * unit)
end -- if number or not
end -- if 'and'
end -- for each word
if #stack == 0 then
return nil, "No number found"
end -- nothing
-- When the input has been parsed, sum all numbers on the stack.
local result = (0)
for _, item in ipairs (stack) do
result = result + item
end -- for
return result
end -- function convert_words_to_numbers