This module contains data on various types of numbers in Finnish.
local export = {numbers = {}}
local numbers = export.numbers
export.additional_number_types = {
{key = "colloquial_counting_form", after = "cardinal"},
{key = "colloquial_ordinal", after = "ordinal"},
{key = "digit_name", after = "ordinal_abbr"},
}
numbers = {
cardinal = "nolla",
ordinal = "nollas",
colloquial_counting_form = "nol",
digit_name = "nolla",
}
numbers = {
cardinal = "yksi",
ordinal = "ensimmäinen",
adverbial = {"kerran", "yhdesti<q:mathematics>"},
multiplier = "yksinkertainen",
distributive = "yksittäin",
colloquial_counting_form = "yy<id:number>",
colloquial_ordinal = {"eka", "ensin"},
digit_name = "ykkönen",
}
numbers = {
cardinal = "kaksi",
ordinal = "toinen",
adverbial = "kahdesti",
fractional = "puolikas",
multiplier = "kaksinkertainen",
distributive = "kaksittain",
colloquial_counting_form = "kaa",
colloquial_ordinal = "toka",
digit_name = "kakkonen",
}
numbers = {
cardinal = "kolme",
ordinal = "kolmas",
adverbial = {"kolmesti", "kolmasti"},
fractional = {"kolmasosa", "kolmannes"},
multiplier = "kolminkertainen",
distributive = "kolmittain",
colloquial_counting_form = {"koo<id:number>", "kol"},
colloquial_ordinal = "kolkki<qq:regional>",
digit_name = "kolmonen",
}
numbers = {
cardinal = "neljä",
ordinal = "neljäs",
adverbial = "neljästi",
fractional = {"neljäsosa", "neljännes"},
multiplier = "nelinkertainen",
distributive = "nelittäin",
colloquial_counting_form = {"nee", "nel"},
colloquial_ordinal = "nelkki<qq:regional>",
digit_name = "nelonen",
}
numbers = {
cardinal = "viisi",
ordinal = "viides",
adverbial = "viidesti",
fractional = {"viidesosa", "viidennes"},
multiplier = "viisinkertainen",
colloquial_counting_form = "vii",
colloquial_ordinal = "viikki<qq:regional>",
digit_name = "viitonen",
}
numbers = {
cardinal = "kuusi<id:number>",
ordinal = "kuudes",
adverbial = "kuudesti",
fractional = {"kuudesosa", "kuudennes"},
multiplier = "kuusinkertainen",
colloquial_counting_form = "kuu<id:six>",
colloquial_ordinal = "kuukki<qq:regional>",
digit_name = "kuutonen",
}
numbers = {
cardinal = "seitsemän",
ordinal = "seitsemäs",
adverbial = "seitsemästi",
fractional = {"seitsemäsosa", "seitsemännes"},
multiplier = "seitsenkertainen",
colloquial_counting_form = {"see<id:seven>", "sei<id:seven>"},
colloquial_ordinal = {"seikki<qq:regional>", "seiska"},
digit_name = {"seiska<qq:informal>", "seitsikko", "seitsemäinen"},
}
numbers = {
cardinal = "kahdeksan",
ordinal = "kahdeksas",
adverbial = "kahdeksasti",
fractional = {"kahdeksasosa", "kahdeksannes"},
multiplier = "kahdeksankertainen",
colloquial_counting_form = "kasi",
colloquial_ordinal = "kakki<qq:regional>",
digit_name = {"kasi<id:eight><qq:colloquial>", "kahdeksikko", "kahdeksainen"},
}
numbers = {
cardinal = "yhdeksän",
ordinal = "yhdeksäs",
adverbial = "yhdeksästi",
fractional = {"yhdeksäsosa", "yhdeksännes"},
multiplier = "yhdeksänkertainen",
colloquial_counting_form = "ysi",
colloquial_ordinal = "ykki<qq:regional>",
digit_name = {"ysi<qq:colloquial>", "yhdeksikkö", "yhdeksäinen"},
}
numbers = {
cardinal = "kymmenen",
ordinal = "kymmenes",
adverbial = "kymmenesti",
fractional = {"kymmenesosa", "kymmenennes"},
multiplier = "kymmenkertainen",
colloquial_counting_form = {"kymppi", "kybä"},
}
-- Cardinals and ordinals for 11-19 are set down below.
numbers = {
colloquial_counting_form = "yytoo",
}
numbers = {
colloquial_counting_form = "kaatoo",
}
numbers = {
colloquial_counting_form = "kootoo",
}
numbers = {
colloquial_counting_form = "neetoo",
}
numbers = {
colloquial_counting_form = "viitoo",
}
numbers = {
colloquial_counting_form = "kuutoo",
}
numbers = {
colloquial_counting_form = "seetoo",
}
numbers = {
colloquial_counting_form = "kasitoo",
}
numbers = {
colloquial_counting_form = "ysitoo",
}
numbers = {
colloquial_counting_form = "kakskyt",
}
numbers = {
colloquial_counting_form = "kolkyt",
}
numbers = {
colloquial_counting_form = "nelkyt",
}
numbers = {
colloquial_counting_form = "viiskyt",
}
numbers = {
colloquial_counting_form = "kuuskyt",
}
numbers = {
colloquial_counting_form = {"seiskyt", "seitkyt"},
}
numbers = {
colloquial_counting_form = "kasikyt",
}
numbers = {
colloquial_counting_form = "ysikyt",
}
numbers = {
cardinal = "sata",
ordinal = "sadas",
fractional = {"sadasosa", "sadannes"},
}
numbers = {
cardinal = "tuhat",
ordinal = "tuhannes",
fractional = {"tuhannesosa", "tuhannennes"},
}
numbers = {
cardinal = "miljoona",
ordinal = "miljoonas",
fractional = {"miljoonasosa", "miljoonannes"},
}
local function power_of(n)
return "1" .. string.rep("0", n)
end
numbers = {
cardinal = "miljardi",
ordinal = "miljardis",
}
numbers = {
cardinal = "biljoona",
ordinal = "biljoonas",
}
numbers = {
cardinal = "biljardi",
ordinal = "biljardis",
}
numbers = {
cardinal = "triljoona",
ordinal = "triljoonas",
}
numbers = {
cardinal = "triljardi",
ordinal = "triljardis",
}
numbers = {
cardinal = "kvadriljoona",
ordinal = "kvadriljoonas",
}
numbers = {
cardinal = "kvintiljoona",
ordinal = "kvintiljoonas",
}
numbers = {
cardinal = "sekstiljoona",
ordinal = "sekstiljoonas",
}
numbers = {
cardinal = "septiljoona",
ordinal = "septiljoonas",
}
numbers = {
cardinal = "oktiljoona",
ordinal = "oktiljoonas",
}
local alt_ordinal = { "yhdes", "kahdes" }
local nth_decades = {
"toista", "kolmatta", "neljättä", "viidettä", "kuudetta",
"seitsemättä", "kahdeksatta", "yhdeksättä", "kymmenettä"
}
local partitives = {
= "kymmentä",
= "sataa",
= "tuhatta",
= "miljoonaa",
= "miljardia",
= "biljoonaa"
}
local MAXIMUM_ONES = 121
local MAXIMUM_FACTORS_MNZ = MAXIMUM_ONES
local MAXIMUM_FACTORS_MT1 = 100000000
local MAXIMUM_FACTORS_ANY = 1000000000
local function set_number(number, cardinal, ordinal)
if not numbers then
numbers = {}
end
numbers.cardinal = cardinal
numbers.ordinal = ordinal
end
local function target_only(items)
if type(items) == "table" then
local result = {}
for _, item in ipairs(items) do
table.insert(result, target_only(item))
end
return result
else
if items and items:find("<") then
return mw.ustring.match(items, "(.-)<")
else
return items
end
end
end
local function prepend(prefix, items)
if type(items) == "table" then
local result = {}
for _, item in ipairs(items) do
table.insert(result, prefix .. item)
end
return result
else
return prefix .. items
end
end
local function append(items, suffix)
if type(items) == "table" then
local result = {}
for _, item in ipairs(items) do
table.insert(result, item .. suffix)
end
return result
else
return items .. suffix
end
end
local function more_than_one_nonzero(...)
local count = 0
for _, v in ipairs(arg) do
if v ~= 0 then count = count + 1 end
end
return count > 1
end
local function make_factor(factor, base, separator)
local factorbase = factor * base
local factor_ord = alt_ordinal or target_only(numbers.ordinal)
if factorbase > MAXIMUM_FACTORS_ANY then return false end
set_number(factorbase,
target_only(numbers.cardinal) .. separator .. partitives,
append(factor_ord, separator .. target_only(numbers.ordinal))
)
return true
end
local function make_factors(base)
local separator = base >= 1000000 and " " or ""
for factor = 2,9 do
if not make_factor(factor, base, separator) then break end
end
end
local function past_maximum(base, hundreds, tens, units)
local factor = hundreds + tens + units
local factorbase = factor * base
if factorbase > MAXIMUM_FACTORS_MNZ and more_than_one_nonzero(hundreds, tens, units) then
return true
end
if factorbase > MAXIMUM_FACTORS_MT1 and math.max(hundreds, tens, units) > 1 then
return true
end
return factorbase > MAXIMUM_FACTORS_ANY
end
local function make_factors_tens_hundreds(base)
local separator = base >= 1000000 and " " or ""
for hundreds=0,900,100 do
for tens=0,90,10 do
if past_maximum(base, hundreds, tens, 0) then break end
for units=0,9 do
if past_maximum(base, hundreds, tens, units) then break end
local factor = hundreds + tens + units
if factor >= 2 then
if not make_factor(factor, base, separator) then break end
end
end
end
end
end
local function make_first_decade(base)
local separator = base >= 1000 and " " or ""
for ones = 1,9 do
if base + ones > MAXIMUM_ONES then break end
local alt_ord = alt_ordinal
set_number(base + ones,
target_only(numbers.cardinal) .. separator .. target_only(numbers.cardinal),
alt_ord and {
target_only(numbers.ordinal) .. separator .. alt_ord,
target_only(numbers.ordinal) .. separator .. target_only(numbers.ordinal)
} or target_only(numbers.ordinal) .. separator .. target_only(numbers.ordinal)
)
end
end
local function make_hundreds()
local base = 100
make_factors(base)
for factor = 1,9 do
local factorbase = factor * base
if factorbase > MAXIMUM_ONES then break end
make_first_decade(factorbase)
for offset = 10,base-1 do
local n = factorbase + offset
if n > MAXIMUM_ONES then break end
set_number(n,
prepend(target_only(numbers.cardinal), target_only(numbers.cardinal)),
prepend(target_only(numbers.ordinal), target_only(numbers.ordinal))
)
end
end
end
local function recurse_down(factorbase, unit)
make_first_decade(factorbase)
for offset = 10,999 do
local n = factorbase + offset * unit
if n > MAXIMUM_ONES then break end
set_number(n,
prepend(target_only(numbers.cardinal) .. " ", target_only(numbers.cardinal)),
prepend(target_only(numbers.ordinal) .. " ", target_only(numbers.ordinal))
)
end
if unit >= 1000 then
for factor = 0,999 do
local n = factorbase + factor / 1000
if n > MAXIMUM_ONES then break end
recurse_down(n, unit / 1000)
end
elseif unit ~= 1 then
error("Illegal state")
end
end
local function expand_power(power3)
local base = 1
for _ = 1,power3 do base = 1000 * base end
make_factors_tens_hundreds(base)
for factor = 1,999 do
recurse_down(factor * base, base / 1000)
end
end
local function remove_link_if(form)
return mw.ustring.find(form, " ") and not mw.ustring.find(form, "%[")
end
-- local function separate_links(form)
-- if not mw.ustring.find(form, " ") or mw.ustring.find(form, "%[") then
-- return form
-- end
-- if mw.ustring.find(form, "<") then
-- local tag_index = mw.ustring.find(form, "<")
-- local before_tag, tag = mw.ustring.sub(form, 1, tag_index - 1), mw.ustring.sub(form, tag_index)
-- return separate_links(before_tag) .. tag
-- end
-- if not mw.ustring.find(form, "") then
-- -- TODO (delink completely)
-- return form
-- end
-- return mw.ustring.gsub(form, "+", "]") .. "<link:>"
-- end
for ones = 1,9 do
local one_ord = alt_ordinal or target_only(numbers.ordinal)
set_number(10 + ones,
target_only(numbers.cardinal) .. nth_decades,
one_ord .. nth_decades
)
end
make_factors(10)
for tens = 20,90,10 do
make_first_decade(tens)
end
make_hundreds()
expand_power(1)
expand_power(2)
local function make_default_ordinal_abbr(num, data)
local tbl = { num .. "." }
local enc = { }
local function visit(ord)
local form
if mw.ustring.match(ord, "nen$") then
form = num .. ":nen"
else
form = num .. ":s"
end
if not enc then
enc = true
table.insert(tbl, form)
end
end
if type(data.ordinal) == "table" then
for _, ord in ipairs(data.ordinal) do
visit(target_only(ord))
end
else
visit(target_only(data.ordinal))
end
return tbl
end
for num, data in pairs(numbers) do
num = tostring(num)
if #num < 10 then -- skip large numbers
if #num >= 4 then
local num_remainder_digits = #num % 3
local left_remainder_digits = num:sub(1, num_remainder_digits)
local right_power_of_3_digits = num:sub(1 + num_remainder_digits)
num = left_remainder_digits .. right_power_of_3_digits:gsub("(...)", " %1")
end
data.ordinal_abbr = data.ordinal_abbr or make_default_ordinal_abbr(num, data)
end
end
local empty_keys = {}
-- remove entries with spaces. we do not want links to them.
for number, form_types in pairs(numbers) do
for form_type, forms in pairs(form_types) do
if type(forms) == "string" then
if remove_link_if(forms) then
form_types = nil
end
elseif type(forms) == "table" then
local source_index = 1
local source_end = #forms
local destination_index = 1
while source_index <= source_end do
local form = forms
if not remove_link_if(form) then
forms = form
destination_index = destination_index + 1
end
source_index = source_index + 1
end
end
end
--if not pairs(form_types)(form_types) then
if not (form_types.cardinal or form_types.ordinal) then
table.insert(empty_keys, number)
end
end
for _, number in ipairs(empty_keys) do
numbers = nil
end
for num = 0,115 do
numbers.wplink = ("%s (luku)"):format(num)
end
return export