Module:Roman numeral
Documentation for this module may be created at Module:Roman numeral/doc
require "string"
-- Args: value, type, case
-- Value is a number
-- Type is one of 'ascii', 'unicode', or 'combining'
-- Case is one of 'upper' or 'lower'
local p = {}
-- 1 2 3 4 5 6 7
-- I V X L C D M
-- 1 5 10 50 100 500 1000
local LA = {
-- Lower Ascii
{"I", 'i'}, {"V", 'v'}, {"X", 'x'},
{"L", 'l'}, {"C", 'c'}, {"D", 'd'}, {"M", 'm'}
}
local UA = {} -- Upper Ascii, special case no need for replacements
local LU = {
-- Lower Unicode
{"I", "ⅰ"}, {"V", "ⅴ"}, {"X", "ⅹ"},
{"L", "ⅼ"}, {"C", "ⅽ"}, {"D", "ⅾ"},
{"M", "ⅿ"}
}
local UU = {
-- Upper Unicode
{"I", "Ⅰ"}, {"V", "Ⅴ"}, {"X", "Ⅹ"},
{"L", "Ⅼ"}, {"C", "Ⅽ"}, {"D", "Ⅾ"},
{"M", "Ⅿ"}
}
local LC = {
-- Lower Combining
{"VIII", "ⅷ"}, {"III", "ⅲ"},
{"XII", "ⅻ"}, {"VII", "ⅶ"}, {"II", "ⅱ"},
{"IV", "ⅳ"}, {"IX", "ⅸ"},
{"VI", "ⅵ"}, {"XI", "ⅺ"},
{"I", "ⅰ"}, {"V", "ⅴ"}, {"X", "ⅹ"},
{"L", "ⅼ"}, {"C", "ⅽ"}, {"D", "ⅾ"},
{"M", "ⅿ"}
}
local UC = {
-- Upper Combining
{"VIII", "Ⅷ"}, {"III", "Ⅲ"},
{"XII", "Ⅻ"}, {"VII", "Ⅶ"}, {"II", "Ⅱ"},
{"IV", "Ⅳ"}, {"IX", "Ⅸ"},
{"VI", "Ⅵ"}, {"XI", "Ⅺ"},
{"I", "Ⅰ"}, {"V", "Ⅴ"}, {"X", "Ⅹ"},
{"L", "Ⅼ"}, {"C", "Ⅽ"}, {"D", "Ⅾ"},
{"M", "Ⅿ"}
}
function p.exec(frame)
local args
-- If called via #invoke, use the args passed into the invoking template.
-- Otherwise, for testing purposes, assume args are being passed directly in.
if frame == mw.getCurrentFrame() then
args = frame:getParent().args
else
args = frame
end
local value = tonumber(args[1])
if value == nil then
return '0'
end
local neg = false
if value == 0 then
return '0';
elseif value < 0 then
neg = true
value = -value
end
local rn = ''
while value >= 1000 do
rn = rn .. string.rep(numeral("M"), value/1000)
value = value % 1000
end
while value ~= 0 do
if value >= 500 then
if value < 900 then
rn = rn .. string.rep("D", value/500)
value = value % 500
else
rn = rn .. "CM"
value = value % 100
end
elseif value >= 100 then
if value < 400 then
rn = rn .. string.rep("C", value/100)
value = value % 100
else
rn = rn .. "CD"
value = value % 100
end
elseif value >= 50 then
if value < 90 then
rn = rn .. string.rep("L", value/50)
value = value % 50
else
rn = rn .. "XC"
value = value % 10
end
elseif value >= 10 then
if value < 40 then
rn = rn .. string.rep("X", value/10)
value = value % 10
else
rn = rn .. "XL"
value = value % 10
end
elseif value >= 5 then
if value < 9 then
rn = rn .. string.rep("V", value/5)
value = value % 5
else
rn = rn .. "IX"
break
end
else
if value < 4 then
rn = rn .. string.rep("I", value)
else
rn = rn .. "IV"
end
break
end
end
local d
if args[2] == 'ascii' then
if args[3] == 'lower' then
d = LA
else
d = UA
end
elseif args[2] == 'unicode' then
if args[3] == 'lower' then
d = LU
else
d = UU
end
else
if args[3] == 'lower' then
d = LC
else
d = UC
end
end
if d ~= UA then
for _, kv in ipairs(d) do
rn = rn:gsub(kv[1], kv[2])
end
end
if neg then
return '-' .. rn
else
return rn
end
end
return p