Для документации этого модуля может быть создана страница Модуль:CenturyMetaCat/doc

---*- mode: lua; coding: utf-8; -*-

local p = {}

-- константы
local ROMAN = {
    I = 1,
    IV = 4,
    V = 5,
    IX = 9,
    X = 10,
    --XL = 40,
    --L = 50,
}

-- переменные
local cent -- век, положительное число
local roman_cent -- век римскими цифрами
local BC   -- 0 == н.э. 1 == до н.э.
local templ -- строка-шаблон вида 'Мир в %s веке%s'
local title = mw.title.getCurrentTitle().text

-- опции
local cent_min -- число, по умолчанию -39, 0 == только н.э.
local cent_max -- число, по умолчанию 21 (XXI век)
local range = 5

-- экспортируемые функции
local getArgs = require('Module:Arguments').getArgs
local sparseIpairs = require('Module:TableTools').sparseIpairs
local toroman = require('Module:Roman').convert
local gsub = mw.ustring.gsub

function roman_to_int(s)
    local i = 1
    local num = 0
    while i <= s:len() do
        local c
        if i < s:len() then
            c = ROMAN[s:sub(i, i+1)]
        end
        if c then
            num = num + c
            i = i + 2
        else
            num = num + ROMAN[s:sub(i, i)]
            i = i + 1
        end
    end
    return num
end

local function get_templ(s)
    -- формируем строку-шаблон вида:
    -- 'Мир в XI веке до н. э.' -> 'Мир в %s веке%s'
    -- определяем BC 
    local t
    t, BC = gsub(s, '[IVX]+ (век[еа]?) до н%. э%.', '%%s %1%%s')
    local n = BC
    if BC ~= 1 then
        t, n = gsub(s, '[IVX]+ (век[еа]?)', '%%s %1%%s')
    end
    if n ~= 1 then
        -- не найдено или найдено больше одного
        error('Век не найден')
    end
    -- в/во, о/об
    t = gsub(t, 'во %%s веке', 'в %%s веке')
    templ = gsub(t, 'об %%s веке', 'о %%s веке')
end

local function get_cent(t)
    _, _, roman_cent = mw.ustring.find(t, '([IVX]+) век')
    if not roman_cent then error('век не найден') end
    cent = roman_to_int(roman_cent)
end

local function format(c, wiki)
    local bcs, t
    if c < 1 then
        c = 1 - c
        bcs = ' до н. э.'
        --t = toroman(c)..' до н. э.'
        t = '-'..toroman(c)
    else
        bcs = ''
        t = toroman(c)
    end
    local s
    if wiki then
        -- в/во, о/об
        local tt = templ
        if c == 2 then
            tt = gsub(tt, 'в %%s веке', 'во %%s веке')
        end
        if c == 11 then
            tt = gsub(tt, 'о %%s веке', 'об %%s веке')
        end
        s = string.format(tt, toroman(c), bcs)
        s = string.format('[[:К:%s|%s]]', s, t)
    else
        s = t
    end
    return s
end

local function navbox()
    local c
    c = cent
    if BC == 1 then
        -- пропускаем 0
        -- I до н.э. c == 0, II до н.э. c == -1 и т.д.
        c = 1 - cent
    end
    local wt = mw.html.create('table'):addClass('standard'):attr('align', 'center')
    local row = wt:tag('tr')
    local cstart
    if cent_min < 1 then
        cstart = math.max(cent_min+1, c - range)
    else
        cstart = math.max(cent_min, c - range)
    end
    local cend = math.min(cent_max, c + range) -- FIXME: до н.э.
    for i = cstart, cend do
        if i == 1 and i ~= cstart then row:tag('th'):wikitext('') end -- разд. до н.э./н.э.
        if i == c then
            row:tag('th'):wikitext(format(i, false))
        else
            row:tag('td'):wikitext(format(i, true))
        end
    end
    return tostring(wt)
end

local function do_expand(s)
-- <век> - век римскими цифрами без слова "век" (XVII)
-- <тысячелетие> - тысячелетие числом (без добавления -е/-м/-го)
-- <ключ> - ключ сортировки, н.э. - номер века числом,
-- до н.э. - отрицательное число начиная с -99 (-99 == I век до н.э. -98 == II век до н.э. и т.д.)
    local mil = math.floor((cent-1)/10)+1 -- тысячелетие
    -- в/во, о/об ?
    if mil == 2 then
        s = gsub(s, ' в <тысячелетие>', ' во <тысячелетие>')
    end
    if BC == 1 then
        s = gsub(s, '<век> (век[еа]?)', roman_cent .. ' %1 до н. э.')
        s = gsub(s, '<тысячелетие>(-[емг][о]? тысячелети[еия])', mil..'%1 до н. э.') -- 2-е/2-м/2-го
        s = gsub(s, '<ключ>', cent-100)
    else
        s = gsub(s, '<век>', roman_cent)
        s = gsub(s, '<тысячелетие>', mil)
        s = gsub(s, '<ключ>', cent)
    end
    return s
end

local function cats(args)
    local c, t
    local ret = ''
    for _, c in sparseIpairs(args) do
        t = mw.text.split(c, '!', true)
        -- диапазон веков для кат.
        local cmin = -99
        if t[3] and t[3] ~= '' then
            cmin = tonumber(t[3])
        end
        local cmax = 99
        if t[4] and t[4] ~= '' then
            cmax = tonumber(t[4])
        end
        local cc = cent
        if BC == 1 then cc = -cent end
        if cc >= cmin and cc <= cmax then
            -- в/во, о/об
            local tt = t[1]
            if cent == 2 then
                tt = gsub(tt, '<век> быуатта')
            end
            if cent == 11 then
                tt = gsub(tt, 'о <век> веке', 'об <век> веке')
            end
            if t[2] and t[2] ~= '' then
                ret = ret .. string.format('[[К:%s|%s]]', tt, t[2])
            else
                ret = ret .. string.format('[[К:%s]]', tt)
            end
        end
    end
    return do_expand(ret)
end

function p.main(frame)
    local args = getArgs(frame)
    title = args['title'] or title
    -- разбор аргументов
    range = tonumber(args['range'] or 5)
    cent_min = tonumber(args['min'] or -39)
    cent_max = tonumber(args['max'] or 21)
    -- нахождение текушего века
    get_cent(title)
    -- создание шаблона-строки
    get_templ(title)
    -- создание навбокса и категорий
    return navbox(title) .. cats(args)
end

function p.expand(frame)
    local args = getArgs(frame)
    title = args['title'] or title
    get_cent(title)
    BC = mw.ustring.find(title, '[IVX]+ век[еа]? до н%. э%.')
    if BC then
        BC = 1
    else
        BC = 0
    end
    --  
    local tt = args[1]
    if cent == 2 then
        tt = gsub(args[1], '<век> быуатта')
    end
    if cent == 11 then
        tt = gsub(tt, 'о <век> веке', 'об <век> веке')
    end
    return do_expand(tt)
end

function p.century_from_title(frame)
    local args = getArgs(frame)
    title = args['title'] or title
    BC = mw.ustring.find(title, '[IVX]+ век[еа]? до н%. э%.')
    get_cent(title)
    if BC then
        return -cent
    end
    return cent
end

return p