Документация
local p = {}
local function First_less_Second(a, b)
local LenA = mw.ustring.len(a)
local LenB = mw.ustring.len(b)
for i = 1, (LenA < LenB) and LenA or LenB do
if mw.ustring.codepoint(a, i, i) ~= mw.ustring.codepoint(b, i, i) then
return mw.ustring.codepoint(a, i, i) < mw.ustring.codepoint(b, i, i)
end
end
return LenA < LenB
end
local function internalFormatNumber(a_number, a_decimalMark, a_groupMark, a_groupMinLength, a_groupOnlyIntegerPart)
-- find the decimal point
local decimalPosition = mw.ustring.find(a_number, ".", 1, true);
local needsGrouping = false;
local DIGIT_GROUPING_SIZE = 3
if (not decimalPosition) then
-- no decimal point - integer number
decimalPosition = mw.ustring.len(a_number) + 1;
if (decimalPosition > a_groupMinLength) then
needsGrouping = true;
end
else
-- decimal point present
if ((decimalPosition > a_groupMinLength) or (((mw.ustring.len(a_number) - decimalPosition) > DIGIT_GROUPING_SIZE) and (not a_groupOnlyIntegerPart))) then
needsGrouping = true;
end
-- replace the decimal point
a_number = mw.ustring.sub(a_number, 1, decimalPosition - 1) .. a_decimalMark .. mw.ustring.sub(a_number, decimalPosition + 1);
end
if (needsGrouping and (decimalPosition > DIGIT_GROUPING_SIZE + 1)) then
-- grouping of integer part necessary
local i = decimalPosition - DIGIT_GROUPING_SIZE;
while (i > 1) do
-- group the integer part
a_number = mw.ustring.sub(a_number, 1, i - 1) .. a_groupMark .. mw.ustring.sub(a_number, i);
decimalPosition = decimalPosition + mw.ustring.len(a_groupMark);
i = i - DIGIT_GROUPING_SIZE;
end
end
-- skip to the end of the new decimal mark (in case it is more than one char)
decimalPosition = decimalPosition + mw.ustring.len(a_decimalMark) - 1;
if (a_groupOnlyIntegerPart) then
needsGrouping = false;
end
if (needsGrouping and ((mw.ustring.len(a_number) - decimalPosition) > DIGIT_GROUPING_SIZE)) then
-- grouping of fractional part necessary
-- using negative numbers (index from the end of the string)
local i = decimalPosition - mw.ustring.len(a_number) + DIGIT_GROUPING_SIZE;
while (i <= -1) do
-- group the fractional part
a_number = mw.ustring.sub(a_number, 1, i - 1) .. a_groupMark .. mw.ustring.sub(a_number, i);
i = i + DIGIT_GROUPING_SIZE;
end
end
return a_number;
end
-- from de:Modul:FormatNum
function formatNum(number)
if (number) then
number = tostring(number)
format = {decimalMark = ",", groupMark = " ", groupMinLength = 5, groupOnlyIntegerPart = true}
-- lua can parse the number (first check passed) and format entry found
local sign = mw.ustring.sub(number, 1, 1);
if ((sign == "+") or (sign == "-")) then
-- remove sign from number, add it later again
number = mw.ustring.sub(number, 2);
else
-- was not a sign
sign = "";
end
if (mw.ustring.sub(number, 1, 1) == ".") then
-- number begins with "." -> add a 0 to the beginning
number = "0" .. number;
else
if (mw.ustring.sub(number, -1) == ".") then
-- number ends with "." -> remove it
number = mw.ustring.sub(number, 1, -2);
end
end
if ((number == mw.ustring.match(number, "^%d+$")) or (number == mw.ustring.match(number, "^%d+%.%d+$"))) then
-- number has valid format (only digits or digits.digits) -> format it and add sign (if any) again
number = sign .. internalFormatNumber(number, format.decimalMark, format.groupMark, format.groupMinLength, format.groupOnlyIntegerPart);
else
-- number has no valid format -> undo all modifications
number = a_frame.args["number"];
end
end
return number;
end
local byte = string.byte
local gmatch = string.gmatch
-- Forward references --
local tab = { -- tab[i][j] = xor(i-1, j-1)
{0, 1, 2, 3, 4, 5, 6, 7, },
{1, 0, 3, 2, 5, 4, 7, 6, },
{2, 3, 0, 1, 6, 7, 4, 5, },
{3, 2, 1, 0, 7, 6, 5, 4, },
{4, 5, 6, 7, 0, 1, 2, 3, },
{5, 4, 7, 6, 1, 0, 3, 2, },
{6, 7, 4, 5, 2, 3, 0, 1, },
{7, 6, 5, 4, 3, 2, 1, 0, },
}
local function bxor (a,b)
local res, c = 0, 1
while a > 0 and b > 0 do
local a2, b2 = a%8, b%8;
res = res + tab[a2+1][b2+1]*c
a,b,c = (a-a2)/8 , (b-b2)/8, c*8
end
res = res + a*c + b*c
return res
end
--local function band (a,b) return ((a+b) - bxor(a,b))/2 end
-- другая реализация band(hash * 16777619, 2^32 - 1)
local function hack(hash)
local mas={ 0x80000000, 0xC0000000, 0x60000000, 0x30000000, 0x98000000, 0x4C000000, 0x26000000, 0x93000000, 0xC9800000, 0x64C00000, 0x32600000, 0x19300000, 0xC980000, 0x64C0000, 0x3260000, 0x1930000, 0xC98000, 0x64C000, 0x326000, 0x193000, 0xC9800, 0x64C00, 0x32600, 0x19300, 0x8000C980, 0x400064C0, 0x20003260, 0x10001930, 0x8000C98, 0x400064C, 0x2000326, 0x1000193, };
local result ,i, step = 0, 1, 0x80000000;
while (hash>0) do
if hash >= step then
result = result + mas[i];
hash = hash - step;
end
i , step = i+1 , step/2;
end
while (result>=0x100000000) do result = result - 0x100000000; end
return result
end
function p.FNV32_1A (str)
local hash = 2166136261
for char in gmatch(str,".") do
hash = bxor(hash, byte(char))
hash = hack(hash) --hash = band(hash * 16777619, 2^32 - 1)
end
return hash
end
local i=0;
function p.hash(str)
str = p.FNV32_1A(str);
return str;
end
-- извращаемся
function decrypt(data)
local i,j=4,2; local result = {data,}
while data[i]~=nil do
result[j] = { data[i] , data[i+1] , data[i+2] };
i = i + 3 ;j=j+1;
end
return result
end
function mypair(t, k)
if(k==nil) then k=0 end
local v = t[k+1]
if(v~=nil) then return k+1,v end
return nil,nil
end
function my__pairs(t)
--mw.log("__pairs работает")
return mypair,t, nil
end
function p.getModule2( num )
local frame=mw.getCurrentFrame()
local modul=frame.args[num]
if(modul==nil) then
modul=mw.loadData("Модуль:Песочница/Туча/Модуль:Statistical/"..num) --mw.log(modul)
if(modul==nil) then return nil end
if(modul[1]~=nil) then -- новый формат модуля
local t = modul
modul={} --mw.log("начало приключений")
local meta4 = {}
function meta4.__index(op, key)
local result = rawget(op,key) -- проверяем не запрашивали ли таблицу ранее
if(result==nil) then
if(t==nil or t[key]==nil) then return nil end
result = {}
local i=t[key] --mw.log("запросили запись ",key)
local meta2 = {}
meta2.__pairs=my__pairs
function meta2.__index(op, key)
if(key==nil or type(key)~="number" or key<1) then return nil end
local result = rawget(op,key) -- проверяем не запрашивали ли таблицу ранее
if(result==nil) then
local index=i+(key-1)*3 --mw.log("mas ",i," ",key)
if(t[index]==nil) then return nil end
result = {}
local meta3 = {}
function meta3.__index(op, key)
if(key==nil or type(key)~="number" or key<1 or key>3) then return nil end
--mw.log("mas[",index+key-1,"]=",t[index+key-1])
return t[index+key-1]
end
setmetatable(result, meta3)
if(result~=nil) then rawset(op,key,result) end
end
return result
end
setmetatable(result, meta2)
if(result~=nil) then rawset(op,key,result) end
end
return result
end
setmetatable(modul, meta4)
end
frame.args[num] = modul
end
return modul;
end
local tableregions = nil
local function regions()
if(tableregions==nil) then
tableregions = require("Модуль:Песочница/Туча/Модуль:Statistical/Regions")
end
return tableregions
end
function p.GetStat(frame)
local args = frame.args
if(args==nil or args[1]==nil) then args = frame:getParent().args end
local PlaceName = nil
if args ~= nil then PlaceName=args[1] end
if PlaceName == nil then return "Введите название объекта АТД" end
local function GetCheck()
local check = args['check'] or '';
check = not (check == '' or check == '0' or check == 'false')
return check;
end
PlaceName = mw.text.trim(PlaceName)
local Region = args['Регион'] or ''
local NumABC,ModulName = nil,nil
if(Region~='') then
ModulName=regions()[Region] or regions()[tonumber(Region)]
if(ModulName==nil) then
mw.log("'"..Region.."' - такого региона нет")
Region=''
end
end
if(Region=='') then
for vskobkah in gmatch(PlaceName,"%((.+)%)") do
if(regions()[vskobkah]) then
Region =vskobkah
ModulName=regions()[Region]
end
--mw.log("Модуль:Statistical: Найдено в скобках '" .. vskobkah.."' -".. (Region~='' and "" or " не") .. " регион");
end
end
if(Region=='') then
-- ё = е , так как по соглашению их не различают при сортировке
local PlaceEEE = mw.ustring.gsub (PlaceName, "ё", "е")
PlaceEEE = mw.ustring.gsub (PlaceEEE, "Ё", "Е")
PlaceEEE = mw.ustring.gsub (PlaceEEE, "-", "")
local ABCmain = mw.loadData(" Модуль:Песочница/Туча/Модуль:Statistical/ABC0")
for k, v in pairs(ABCmain) do
-- mw.ustring.lower для регистроНЕзависимого сравнения
if First_less_Second(mw.ustring.lower(PlaceEEE), mw.ustring.lower(v)) then break else NumABC = k end
end
end
local function FormatH()
return p.hash(PlaceName)
end
local Format = mw.text.trim ( (args[2] or "Таблица"))
local Place,pos=PlaceName,nil
if(ModulName==nil and NumABC ~= nil) then
local num = frame:expandTemplate{ title = "Участник:Туча/Население/ABC"..NumABC, args = { Place } }
if num == '' then
Place = FormatH()
num = frame:expandTemplate{ title = "Участник:Туча/Население/ABC"..NumABC, args = { Place } }
end
num = tonumber(num)
ModulName = num and regions()[num]
end
local RegionData = nil
if(ModulName~=nil) then
RegionData = p.getModule2("RUS-"..ModulName)
if(pos==nil) then if RegionData[Place] == nil then pos = FormatH() else pos=Place end end
end
local PlaceData = (RegionData and RegionData[pos]) or nil
if PlaceData == nil then
if GetCheck() then
return 0;
elseif Format == 'Хеш' or Format == 'х' then
return FormatH()
else
return "#Н/Д"..frame:extensionTag{name = 'ref', content = PlaceName .." > Данные не обнаружены. Возможно страница переименовывалась. Проверьте справочник" .. ((args.nocat and "") or "[[Категория:Википедия:Статьи с неправильными параметрами шаблона Население]]")} ;
end
end
if GetCheck() then return 1; end
if (type(PlaceData[1])=="number") then PlaceData = decrypt(PlaceData) end
local LastRecord = 0
for k in pairs(PlaceData) do LastRecord = LastRecord + 1 end
local NumRecord = LastRecord
local function FormatY()
return PlaceData[NumRecord][1]
end
local function FormatN()
return PlaceData[NumRecord][2]
end
local function FormatS(SourceType)
if PlaceData[NumRecord][3] == "" then
return ""
else
local Source1
local Source2
if string.find(PlaceData[NumRecord][3],"%d+[A-Z]+")==1 then
Source1 = "{{Население/" .. PlaceData[NumRecord][3].."}}"
Source2 = PlaceData[NumRecord][3]
else
Source1 = PlaceData[NumRecord][3]
Source2 = ""
end
if string.find(Source1, "http://")==1 then
Source1 = '['..Source1..']'
end
if SourceType == "и" then
return Source1
end
if Source2 == "" then
return frame:callParserFunction{name = '#tag:ref', args = {Source1}}
else
return frame:callParserFunction{name = '#tag:ref', args = {Source1, name = Source2}}
end
end
end
local function FormatF()
return formatNum(PlaceData[NumRecord][2])
end
local function FormatT()
if NumRecord > 1 then
if PlaceData[NumRecord][2] > PlaceData[NumRecord - 1][2] then
return "<span style='color: #0c0; font-weight:bold; font-size: larger;'>↗</span>"
elseif PlaceData[NumRecord][2] < PlaceData[NumRecord - 1][2] then
return "<span style='color: red; font-weight:bold; font-size: larger;'>↘</span>"
else
return "<span style='color:#0AF;'>→</span>"
end
else
return ""
end
end
--mw.log("количество записей ",NumRecord)
if Format == 'Год' or Format == 'г' then
return FormatY()
elseif Format == 'Безформат' or Format == 'Число' or Format == 'ч' then
return FormatN()
elseif Format == 'Ссылка' or Format == 'с' then
return FormatS("с")
elseif Format == 'Источник' or Format == 'и' then
return FormatS("и")
elseif Format == 'Формат' or Format == 'ф' then
return FormatF()
elseif Format == 'Формат' or Format == 'фг' then
return FormatF().." ("..FormatY()..")"
elseif Format == 'Формат' or Format == 'фс' then
return FormatF()..FormatS()
elseif Format == 'ФорматСсылкаГод' or Format == 'фсг' then
return FormatF()..FormatS().." ("..FormatY()..")"
elseif Format == 'Тренд' or Format == 'т' then
return FormatT()..FormatF()
elseif Format == 'Значение' or Format == 'ТрендСсылка' or Format == 'тс' then
return FormatT()..FormatF()..FormatS()
elseif Format == 'ТрендСсылкаГод' or Format == 'тсг' then
return FormatT()..FormatF()..FormatS().." ("..FormatY()..")"
elseif Format == 'Хеш' or Format == 'х' then
return FormatH()
elseif Format == 'Диаграмма' or Format == 'д' then
local tempHeight = 370
local tempWidth = 800
local tempMod = math.fmod (LastRecord, 5)
if LastRecord < 40 then
tempHeight = 200 + 170 * (LastRecord - 1) / 40
tempWidth = 200 + 600 * (LastRecord - 1) / 40
end
local tempGroup = ""
local tempTooltip = ""
local tempLegend = ""
for k in pairs(PlaceData) do
NumRecord = k
tempGroup = tempGroup .. FormatN() .. ":"
tempTooltip = tempTooltip .. FormatF() .. " (" .. FormatY() .. "):"
if LastRecord < 5 or math.fmod (k, 5) == tempMod then tempLegend = tempLegend .. FormatY() end
tempLegend = tempLegend .. ":"
end
tempGroup = string.sub (tempGroup, 1, string.len (tempGroup)-1)
tempTooltip = string.sub (tempTooltip, 1, string.len (tempTooltip)-1)
tempLegend = string.sub (tempLegend, 1, string.len (tempLegend)-1)
local barChart = require('Модуль:Chart')['bar chart'];
local Diagram = {
['height'] = tempHeight,
['width'] = tempWidth,
['group 1'] = tempGroup,
['tooltip 1'] = tempTooltip,
['x legends'] = tempLegend,
['group names'] = 'Численность населения',
['default color'] = '#00CCFF'
}
local cframe = mw.getCurrentFrame();
return barChart(cframe:newChild{ title=cframe.title, args = Diagram})
else
-- Формироание HTML-таблицы
local HtmlBuilder = require('Модуль:HtmlBuilder')
local HTML = HtmlBuilder.create('table')
local MaxData
if args['Столбцов'] then
Column = tonumber(args['Столбцов'])
else
MaxData = (PlaceData[1][2] > PlaceData[LastRecord][2]) and PlaceData[1][2] or PlaceData[LastRecord][2]
if MaxData < PlaceData[math.floor((LastRecord + 1) / 2)][2] then MaxData = PlaceData[math.floor((LastRecord + 1) / 2)][2] end
if MaxData < 10 then Column = 15
elseif MaxData < 100 then Column = 12
elseif MaxData < 1000 then Column = 12
elseif MaxData < 10000 then Column = 12
elseif MaxData < 100000 then Column = 10
elseif MaxData < 1000000 then Column = 10
elseif MaxData < 10000000 then Column = 8
elseif MaxData < 100000000 then Column = 8
else Column = 7 end
if Column > LastRecord then Column = LastRecord end
end
if args['Оформление'] ~= nil then
HTML.attr('class', args['Оформление'])
else
if Column > 7 then HTML.attr('class', 'wide') else HTML.attr('class', 'standard') end
end
local TempRow
local NumRow = 0
TempRow = HTML.tag('th').attr('colspan', Column).wikitext(args['Заголовок'] or 'Численность населения')
for i = 1, math.ceil(LastRecord / Column) do
TempRow = HTML.tag('tr').addClass("bright")
for j = 1, Column do
NumRecord = (i - 1) * Column + j
if PlaceData[NumRecord] == nil then
TempRow.tag('th').wikitext("")
else
TempRow.tag('th').wikitext(FormatY()..FormatS("с"))
end
end
TempRow = HTML.tag('tr').attr('align', 'center')
for j = 1, Column do
NumRecord = (i - 1) * Column + j
if PlaceData[NumRecord] == nil then
TempRow.tag('td').wikitext("")
else
TempRow.tag('td').wikitext(FormatT()..FormatF())
end
end
end
return tostring(HTML)
end
return 1, Format
end
function p.GetRegion(frame)
local args = frame.args
if(args==nil or args[1]==nil) then args = frame:getParent().args end
local PlaceName = nil
if args ~= nil then PlaceName=args[1] end
return PlaceName:match("%((%P+)%)")
end
return p