Module:Sandbox/Squc/Roman
This module converts Roman numerals to decimal form, and rejects invalid ones. It can be used normally, or through another module. This is still under construction, check back in a few days!
This module is intended to run through a template, which is still under construction.
To convert Roman numerals to decimal form, use {{#invoke:Sandbox/Squc/Roman|todecimal|MMXIII}}
, which outputs 2013. If the Roman numeral is invalid, it will throw an error. If JavaScript is enabled, you can click the Script error link, and the first sentence should show the cause of the error. The final value will still be given in brackets after the error messages.
To force no errors, use {{#invoke:Sandbox/Squc/Roman|todecimal|MMXIII}}
.
To output errors directly into the text, use {{#invoke:Sandbox/Squc/Roman|todecimal|MMXIII}}
.
To use this through another module, use something like this:
local roman = require( "Module:Sandbox/Squc/Roman" )
local romannum = "MMXIII"
local value = roman.todecimald( romannum )
function | No errors | Warnings | Invalid | Errors |
---|---|---|---|---|
Example | MMXIII | XXXXX | XCC | ABC |
todecimal | 2013 | Lua error at line 116: More than four X in a row, suggestion: L? - Char 5. | Lua error at line 116: Repeat after subtraction - XCC - Char 3. | Lua error at line 116: Extra characters AB found. |
todecimal|mode=1 | 2013 | Lua error at line 116: More than four X in a row, suggestion: L? - Char 5. | Lua error at line 116: Repeat after subtraction - XCC - Char 3. | Lua error at line 116: Extra characters AB found. |
todecimal|mode=2|disp=Decimal ... | 2013 | Lua error at line 116: More than four X in a row, suggestion: L? - Char 5. | Lua error at line 116: Repeat after subtraction - XCC - Char 3. | Lua error at line 116: Extra characters AB found. |
todecimald | Intended for use only from other modules. See below for more details. |
Errors will be combined, e.g. "XXXXXXCC" gives:
Lua error at line 116: More than four X in a row, suggestion: L? - Char 5; Number of X before C must be at most two - Char 7; Repeat after subtraction - XCC - Char 8.
or with mode=2|disp=0 (default):
Lua error at line 116: More than four X in a row, suggestion: L? - Char 5; Number of X before C must be at most two - Char 7; Repeat after subtraction - XCC - Char 8.
- todecimald
The function todecimald (direct) is only intended for use in other modules. The output will be in the form (comma-separated list): Decimal, Error message, Time taken
The decimal will be a number, it will be the converted number if there are no errors or if it is a warning (it is invalid but still can be converted), it will be -1 if there is an error (cannot be converted). The error message is a string and will always exist, it will be ""
if no error is found.
-- Module to convert Roman numerals and reject invalid numerals
local p={}
local function todec ( rnum )
local err = ""
if rnum == "" then return -1, ("Input is empty") end
if type(rnum) ~= "string" then return -1, ("Input is not a string") end
rnum = rnum:upper()
rnum = rnum:match"^%s*(.*%S)"
local space = rnum:gsub("[^ \t\r\n\v\f]","")
if #space ~= 0 then
err = (err .. "Whitespace found in middle of string, ")
rnum = rnum:gsub("[ \t\r\n\v\f]","")
end
local extra = rnum:gsub("[MDCLXVI]","")
if #extra ~= 0 then return -1, ("Extra characters " .. extra .. " found") end
local value = {
I = 1,
V = 5,
X = 10,
L = 50,
C = 100,
D = 500,
M = 1000
}
local symbol = {}
for i,v in pairs(value) do symbol[v] = i end -- reverse value table
local prev, curr, cu1d, run, num = 0,0,0,0,0
local psym, csym = "","" -- previous symbol, current symbol
for i = 1, #rnum do
csym = rnum:sub(i, i)
local curr = value[ csym ]
cu1d = tostring( curr ):sub( 1, 1 ) -- first digit of curr (1 or 5)
if curr < prev or prev == 0 then
num = num + prev*run
run = 1
elseif curr == prev then
if cu1d == "1" then
if run == 4 then -- e.g. "XXXXX" for 50, "L" suggested
err=(err.."More than four " .. csym .. " in a row, suggestion: " .. symbol[ curr*5 ] .. "? - Char " ..tostring(i).."; ")
run = run + 1
elseif run == 0 then -- e.g. occurs after curr > prev (below) e.g. "XCC"
err=(err.."Repeat after subtraction - " .. rnum:sub(i-2, i-2) .. psym .. csym .. " - Char " ..tostring(i).."; ")
run = 1 -- In "XCC", assume "XC" is a unit, so the current "C" is counted separately.
else
run = run + 1
end
elseif cu1d == "5" then -- e.g. "VV" for 10, "X" suggested
err=(err..psym .. " cannot be with another ".. csym ..", suggestion: " .. symbol[curr*2] .. "? - Char " ..tostring(i).."; ")
else return -1, ("Unknown error 1") end
elseif curr > prev then
if curr > prev * 10 then -- e.g. "XM" or "IL"
err=(err..csym .. " cannot follow " .. psym .. " (Subtraction can only be within the same digit) Char " ..tostring(i).."; ")
elseif tostring( prev ):sub(1, 1) == "5" then -- e.g. "LC" for 50
err=(err..csym .. " cannot follow " .. psym .. " (Cannot subtract from " .. tostring(prev) .. ") Char " ..tostring(i).."; ")
elseif run > 2 then -- e.g. "XXXL" for 20
err=(err.."Number of " .. psym .. " before " .. csym .. " must be at most two - Char " ..tostring(i).."; ")
end
num = num - prev*run + curr
run = 0
else return -1, ("Unknown error 2") end
prev = curr
psym = csym
end
num = num + prev*run
if err ~= "" then err = err:sub(1, -3) end
return num, err
end
function p.todecimald( frame )
return todec( frame )
end
function p.todecimalv( frame )
local input = frame.args[1]
local num, err = todec( input )
if num == nil then return err
elseif err == "" then
if num ~= -1 then return num
else return "Unknown error 3" end
else
if num ~= -1 then return (err.." ("..num..")")
else return err end
end
end
function p.todecimalf( frame )
local input = frame.args[1]
local num, err = todec( input )
if num ~= -1 then return num
else
if err ~= "" then error(err)
else error("Unknown error 3") end
end
end
function p.todecimal( frame )
local input = frame.args[1]
local num, err = todec( input )
if err == "" then
if num ~= -1 then return num
else error("Unknown error 3") end
else
error(err)
end
end
return p