Модуль:CenturyMetaCat
Для документации этого модуля может быть создана страница Модуль: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