From Wikipedia, the free encyclopedia

-- This module implements {{Roman}}.

require[[strict]]



local p = {}



-- This function implements the {{overline}} template.

local function overline(s)

    return mw.ustring.format( '<span style="text-decoration:overline;">%s</span>', s )

end



-- Gets the Roman numerals for a given numeral table. Returns both the string of

-- numerals and the value of the number after it is finished being processed.

local function getLetters(num, t)

    local ret = {}

    for _, v in ipairs(t) do

        local val, letter = unpack(v)

        while num >= val do

            num = num - val

            table.insert(ret, letter)

        end

    end



    return table.concat(ret), num

end



-- The main control flow of the module.

local function _main(args)

    -- Get input and exit displaying nothing if the input is empty.

    if args1 == nil then return end

    local num = tonumber(args1])

    if not num or num < 0 or num == math.huge then

    	error('Invalid number ' .. args1], 2)

    elseif num == 0 then

        return 'N'

    end



    -- Return a message for numbers too big to be expressed in Roman numerals.

    if num >= 5000000 then

        return args2 or 'N/A'

    end



    local ret = ''

    -- Find the Roman numerals for the large part of numbers.

    -- 23 April 2016 - tweaked to >= 4000 to accept big Roman 'IV'

    -- The if statement is not strictly necessary, but makes the algorithm 

    -- more efficient for smaller numbers.

    if num >= 4000 then

        local bigRomans = {

            { 1000000, 'M' },

            { 900000, 'CM' }, { 500000, 'D' }, { 400000, 'CD' }, { 100000, 'C' },

            {  90000, 'XC' }, {  50000, 'L' }, {  40000, 'XL' }, {  10000, 'X' },

            {   9000, 'IX' }, {   5000, 'V' }, {   4000, 'IV' },

        }

        local bigLetters

        bigLetters, num = getLetters(num, bigRomans)

        ret = overline(bigLetters)

    end



    -- Find the Roman numerals for numbers less than the big Roman threshold.

    local smallRomans = {

        { 1000, 'M' },

        { 900, 'CM' }, { 500, 'D' }, { 400, 'CD' }, { 100, 'C' },

        {  90, 'XC' }, {  50, 'L' }, {  40, 'XL' }, {  10, 'X' },

        {   9, 'IX' }, {   5, 'V' }, {   4, 'IV' }, {   1, 'I' }

    }

    local smallLetters = getLetters( num, smallRomans )

    ret = ret .. smallLetters



    if args.fraction == 'yes' then

        -- Find the Roman numerals for the fractional parts of numbers.

        -- If num is not a whole number, add half of 1/1728 (the smallest unit) to equate to rounding.

        -- Ensure we're not less than the smallest unit or larger than 1 - smallest unit

        -- to avoid getting two "half" symbols or no symbols at all

        num = num - math.floor(num)

        if num ~= 0 then

            num = math.max(1.1/1728, math.min(1727.1/1728, num + 1/3456))

        end

        local fractionalRomans = {

            { 1/2, 'S' }, { 5/12, "''':'''•''':'''" }, { 1/3, "'''::'''" },

            { 1/4, "''':'''•" }, { 1/6, "''':'''" }, { 1/12, '•' },

            { 1/24, 'Є' }, { 1/36, 'ƧƧ' }, { 1/48, 'Ɔ' }, { 1/72, 'Ƨ' }, { 1/144, '<s>Ƨ</s>' },

            { 1/288, '℈' }, { 1/1728, '»' },

        }

        local fractionalLetters = getLetters(num, fractionalRomans)

        

        ret = ret .. fractionalLetters

    end



    return ret

end



function p.main(frame)

    -- If called via #invoke, use the args passed into the invoking

    -- template, or the args passed to #invoke if any exist. Otherwise

    -- assume args are being passed directly in from the debug console

    -- or from another Lua module.

    local origArgs

    if frame == mw.getCurrentFrame() then

        origArgs = frame:getParent().args

        for k, v in pairs(frame.args) do

            origArgs = frame.args

            break

        end

    else

        origArgs = frame

    end

    -- Trim whitespace and remove blank arguments.

    local args = {}

    for k, v in pairs(origArgs) do

        if type( v ) == 'string' then

            v = mw.text.trim(v)

        end

        if v ~= '' then

            argsk = v

        end

    end

    

    -- exit if not given anything

    if args == nil or args == {} then return end

    -- Given mathematical expression, simplify to a number

    if type(args1]) == 'string' then

        local success, result = pcall(mw.ext.ParserFunctions.expr, args1])

        if success then

            args1 = result

        end -- else, pass to _main routine and try to let Lua's tonumber handle it

    end

    return _main(args)

end



return p