Kontent qismiga oʻtish

Modul:Roman

Vikipediya, erkin ensiklopediya
2025-yil 21-iyun, 13:33 dagi Bekipediya (munozara | hissa) versiyasi
(farq) ←Avvalgi koʻrinishi | Hozirgi koʻrinishi (farq) | Yangiroq koʻrinishi→ (farq)

-- This module implements {{Roman}}.

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

-- This function contains the core logic for converting numbers to Roman numerals.
-- It is designed to be called by both p.main (for #invoke) and p.toRoman (for module-to-module calls).
local function _getRomanNumerals(num_input)
    -- Get input and exit displaying nothing if the input is empty.
    if num_input == nil then return end
    local num = tonumber(num_input)
    if not num or num < 0 or num == math.huge then
    	error('Invalid number ' .. tostring(num_input), 2) -- tostring qo'shildi
    elseif num == 0 then
        return 'N'
    end

    -- Return a message for numbers too big to be expressed in Roman numerals.
    if num >= 5000000 then
        -- Agar _main dan chaqirilmasa, args[2] mavjud bo'lmaydi.
        -- Shuning uchun aniq N/A qaytaramiz.
        return '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

    -- The fractional part logic is typically not needed for century/year conversion
    -- but if you want to enable it for p.main, you would pass a 'fraction' arg.
    -- For direct module calls (p.toRoman), we assume no fractions.
    -- if args.fraction == 'yes' then ... end

    return ret
end

-- The main entry point for #invoke.
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
        -- Check if frame.args are explicitly provided to #invoke (e.g., {{#invoke:Roman|main|123}})
        -- If not, fall back to parent frame's args (e.g., {{Roman|123}})
        if next(frame.args) then -- next(table) returns nil if table is empty
             origArgs = frame.args
        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
            args[k] = v
        end
    end
    
    -- exit if not given anything
    if args == nil or next(args) == nil then return '' end -- next(args) == nil tekshiruvi yaxshiroq
    
    -- Given mathematical expression, simplify to a number
    -- mw.ext.ParserFunctions.expr is not always available in all Lua environments.
    -- This part might need adjustment depending on your Wiki's setup.
    if type(args[1]) == 'string' and mw.ext and mw.ext.ParserFunctions and mw.ext.ParserFunctions.expr then
        local success, result = pcall(mw.ext.ParserFunctions.expr, args[1])
        if success then
            args[1] = result
        else
            -- Agar expr xato bersa, asl stringni saqlab qolamiz va _getRomanNumerals ichida tonumber xato beradi
            -- yoki siz bu yerda boshqacha ishlov berishingiz mumkin.
            -- Hozircha shunchaki asl qiymatni qoldiramiz.
        end
    end
    
    -- p.main _getRomanNumerals funksiyasiga args[1] ni beradi
    return _getRomanNumerals(args[1])
end

-- The new entry point for direct module-to-module calls (e.g., from Module:Wikidata/date).
-- This function converts a given number directly to Roman numerals.
function p.toRoman(number_input)
    -- We simply call our core logic function with the provided number.
    return _getRomanNumerals(number_input)
end

return p