Module:Roman
More actions
Summary
This module contains functions for working with Roman numerals. Currently used by:
Using this module from templates
Numeral
This function converts an Arabic numeral into a Roman numeral. It works for values between 0 (N) and 4999999999 (M̿M̿M̿M̿C̿M̿X̿C̿I̿X̿C̅M̅X̅C̅I̅X̅CMXCIX): this includes the whole range of unsigned 32-bit integers. The output string no longer contain HTML tags. If needed you can add external CSS formatting using a serif font family, or a small-caps font variant. Arabic numeral zero is output as 'N' (for Classical Latin adverbs "Nec" or "non"), like in standard CLDR Data.
If the input does not look like it contains a number or the number is outside of the supported range, an error message is returned. If an error message is returned, the error message will contain code to categorize pages into Category:Errors reported by Module Roman.
Usage:
{{#invoke:Roman|Numeral|''value''}}
Example:
{{#invoke:Roman|Numeral|8}} produces VIII.
Arabic
This function converts a Roman numeral into an Arabic numeral. It works for values between 0 (N) and 4999999999 (M̿M̿M̿M̿C̿M̿X̿C̿I̿X̿C̅M̅X̅C̅I̅X̅CMXCIX): this includes the whole range of unsigned 32-bit integers.
If the input does not look like it contains a number or the number is outside of the supported range, an error message is returned. If an error message is returned, the error message will contain code to categorize pages into Category:Errors reported by Module Roman.
Usage:
{{#invoke:Roman|Arabic|''value''}}
Example:
{{#invoke:Roman|Arabic|viii}} produces Script error: The function "Arabic" does not exist..
Using this module from Lua code
In order to use the functions in this module from another Lua module you first have to import this module.
Example:
local roman = require('Module:Roman')
_Numeral
This function converts an Arabic numeral into a Roman numeral. It works for values between 0 and 4999999. The output string may contain HTML tags. Arabic numeral zero is output as an empty string. If the input does not look like it contains a number or the number is outside of the supported range an error message is returned. If an error message is returned, the error message will contain code to categorize pages into Category:Errors reported by Module Roman.
Usage:
roman_value = roman._Numeral(value)
isRoman
Tests if the input is a valid Roman numeral. Returns true if so, false if not. For the purposes of this function, the empty string is not a valid Roman numeral.
Usage:
if roman.isRoman(roman_value) then
toArabic
This function converts a Roman numeral into an Arabic numeral. It works for values between 0 and 4999999999. The string 'N' is converted to zero. If the input is not a valid Roman numeral this function attempts to parse it as an Arabic number and returns nil if it also fails.
Usage:
arabic_value = roman.toArabic(value)
--[[
This module converts Arabic numerals into Roman numerals. It currently works for any
whole number between 0 and 4999999.
Please do not modify this code without applying the changes first at Module:Roman/sandbox and testing
at Module:Roman/sandbox/testcases and Module talk:Roman/sandbox/testcases.
Authors and maintainers:
* User:RP88
]]
local p = {}
-- =======================================
-- === Public Functions ==================
-- =======================================
--[[
Numeral
This function converts an Arabic numeral into a Roman numeral. It works for values between
0 and 4999999. The output string may contain HTML tags. Arabic numeral zero is output as
an empty string.
Usage:
{{#invoke:Roman|Numeral|<value>}}
{{#invoke:Roman|Numeral}} - uses the caller's parameters
Parameters
1: Value to convert into a Roman numeral. Must be at least 0 and less than 5,000,000.
Error Handling:
If the input does not look like it contains a number or the number is outside of the
supported range an error message is returned.
]]
function p.Numeral(frame)
-- if no argument provided than check parent template/module args
local args = frame.args
if args[1]==nil then
args = frame:getParent().args
end
return p._Numeral(args[1])
end
--[[
_Numeral
This function returns a string containing the input value formatted as a Roman numeral. It works for values between
0 and 4999999. The output string may contain HTML tags.
Parameters
input: integer or string containing value to convert into a Roman numeral
Error Handling:
If the input does not look like it contains a number or the number is outside of the
supported range an error message is returned.
]]
function p._Numeral(input)
local output = ''
if input then
local value = tonumber(input)
if value and (value >= 0) and (value < 5000000) then
output = convertArabicToRomanHTML(value)
else
output = outputError("unsupported value")
end
else
output = outputError("missing value")
end
return output
end
--[[
isRoman
Tests if the input is a valid Roman numeral. Returns true if so, false if not. For the
purposes of this function, the empty string is not a Roman numeral.
Parameters
s: string to test if it is a valid Roman numeral
Error Handling:
If the input is not a valid Roman numeral this function returns false.
]]
function p.isRoman(s)
return s and (s ~= '') and (p.toArabic(s) ~= 0)
end
--[[
toArabic
This function converts a Roman numeral into an Arabic numeral. It works for values between
0 and 4999999. The empty string is converted to zero.
Parameters
roman: string containing value to convert into an Arabic numeral
Error Handling:
If the input is not a valid Roman numeral this function returns zero.
]]
function p.toArabic(roman)
local result = 0
if roman and (type(roman)=='string') and (roman ~= '') then
roman = mw.ustring.lower(mw.text.trim(roman))
result = convertRomanHTMLToArabic(roman)
end
return result
end
-- =======================================
-- === Private Functions =================
-- =======================================
local overline_start = '<span style="text-decoration:overline;">'
local overline_end = '</span>'
--[[
This function returns a string containing the input value formatted as a Roman numeral. It works for values between
0 and 4999999. The result string may contain HTML tags.
]]
function convertArabicToRomanHTML(value)
local result = ''
if (value < 5000) then
result = convertArabicToRoman(value)
else
local low_value
if (math.floor(value) % 5000) >= 4000 then
low_value = math.floor(value) % 1000;
else
low_value = math.floor(value) % 5000;
end
local high_value = math.floor((value - low_value) / 1000)
local low_roman = convertArabicToRoman(low_value)
local high_roman = convertArabicToRoman(high_value)
result = overline_start .. high_roman .. overline_end .. low_roman
end
return result
end
--[[
This function returns a string containing the input value formatted as a Roman numeral. It works for values between
0 and 4999. The result string will be a simple alphabetic string.
]]
function convertArabicToRoman(value)
local thousands = {'', 'M', 'MM', 'MMM', 'MMMM'}
local hundreds = {'', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM'}
local tens = {'', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'}
local ones = {'', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'}
local index
local result = ''
if ((value >= 0) and (value < 5000)) then
index = (math.floor(value / 1000) % 5) + 1
result = result .. thousands[index]
index = (math.floor(value / 100) % 10) + 1
result = result .. hundreds[index]
index = (math.floor(value / 10) % 10) + 1
result = result .. tens[index]
index = (math.floor(value) % 10) + 1
result = result .. ones[index]
end
return result
end
--[[
This function converts a string containing a Roman numeral to an integer. It works for values between
0 and 4999999. The input string may contain HTML tags.
]]
function convertRomanHTMLToArabic(roman)
local result = 0
if mw.ustring.find(roman, "^[mdclxvi]+$") ~= nil then
result = convertRomanToArabic(roman)
else
local overline_start_len = mw.ustring.len(overline_start)
if mw.ustring.sub(roman, 1, overline_start_len) == overline_start then
local end_tag_start, end_tag_end = mw.ustring.find(roman, overline_end, overline_start_len, true)
if end_tag_start ~= nil then
local roman_high = mw.ustring.sub(roman, overline_start_len + 1, end_tag_start - 1)
local roman_low = mw.ustring.sub(roman, end_tag_end + 1, mw.ustring.len(roman)) or ''
if (mw.ustring.find(roman_high, "^[mdclxvi]+$") ~= nil) and (mw.ustring.find(roman_low, "^[mdclxvi]*$") ~= nil) then
result = convertRomanToArabic(roman_high) * 1000 + convertRomanToArabic(roman_low)
end
end
end
end
return result
end
--[[
This function converts a string containing a Roman numeral to an integer. It works for values between
0 and 4999.
]]
function convertRomanToArabic(roman)
local romanDecimals = {m = 1000, d = 500, c = 100, l = 50, x = 10, v = 5, i = 1}
local prevRomanDecimal = 0
local result = 0
for i = mw.ustring.len(roman), 1, -1 do
local c = mw.ustring.sub(roman, i, i)
local currentRomanDecimal = romanDecimals[c]
if currentRomanDecimal == nil then
return 0
end
if prevRomanDecimal > currentRomanDecimal then
result = result - currentRomanDecimal
else
result = result + currentRomanDecimal
end
prevRomanDecimal = currentRomanDecimal
end
return result
end
--[[
Helper function to handle error messages.
]]
function outputError(error_str)
local error_str = '<strong class="error">Roman Module Error: ' .. error_str .. '</strong>';
error_str = '[[Category:Errors reported by Module Roman]]' .. error_str;
return error_str;
end
return p