Модуль:Statistical
Для документации этого модуля может быть создана страница Модуль:Statistical/doc
local p = {}
-- local ABCmain = mw.loadData("Модуль:Statistical/ABC0")
local Regions = mw.loadData("Модуль:Statistical/Regions")
bit32 = require( 'bit32' )
local function LimitDouble(Val)
local MaxNumber = 2147483648
return Val - (math.floor(Val / MaxNumber) * MaxNumber)
end
local function shl(Val, Shift)
if Shift > 0 then
return LimitDouble(Val * (2 ^ Shift))
else
return Value
end
end
local function shr(Val, Shift)
if Shift > 0 then
return math.floor(Val / (2 ^ Shift))
else
return Val
end
end
local function MakeHash(PlaceName)
local dataLength = mw.ustring.len(PlaceName)
if dataLength == 0 then return 0 end
local hash = dataLength
local remainingBytes = math.fmod(dataLength, 2)
local numberOfLoops = math.floor(dataLength / 2)
local currentIndex = 0
local tmp = 0
while (numberOfLoops > 0) do
--do return numberOfLoops end
-- if numberOfLoops ==3 then return mw.ustring.codepoint(PlaceName, currentIndex + 1) .. " - " .. currentIndex end
hash = LimitDouble(hash + mw.ustring.codepoint(PlaceName, currentIndex + 1))
tmp = bit32.bxor(shl(mw.ustring.codepoint(PlaceName, currentIndex + 2), 11), hash)
-- do return PlaceName .. " - " .. hash .. " - " .. tmp .. " - " .. mw.ustring.codepoint(PlaceName, currentIndex + 1) .. " - " .. mw.ustring.codepoint(PlaceName, currentIndex + 2) .. " - " .. mw.ustring.codepoint(PlaceName, currentIndex + 3) end
hash = bit32.bxor(shl(hash, 16), tmp)
hash = LimitDouble(hash + shr(hash, 11))
currentIndex = currentIndex + 2
numberOfLoops = numberOfLoops - 1
end
--do return PlaceName .. " - " .. hash end
if remainingBytes == 1 then
hash = LimitDouble(hash + mw.ustring.codepoint(PlaceName, currentIndex + 1))
hash = bit32.bxor(hash, shl(hash, 10))
hash = LimitDouble(hash + shr(hash, 1))
end
hash = bit32.bxor(hash, shl(hash, 3))
hash = LimitDouble(hash + shr(hash, 5))
--do return PlaceName .. " - " .. hash end
hash = bit32.bxor(hash, shl(hash, 4))
hash = LimitDouble(hash + shr(hash, 17))
hash = bit32.bxor(hash, shl(hash, 25))
hash = LimitDouble(hash + shr(hash, 6))
return hash
end
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
function p.GetStat(frame)
local args = frame:getParent().args
if args == nil then return "Введите название объекта АТД" end
local PlaceName = args[1]
if PlaceName == nil then return "Введите название объекта АТД" end
PlaceName = mw.text.trim(PlaceName)
local Region = args['Регион'] or ''
local check = args['check'] or ''
if check == '' or check == '0' or check == 'false' then
check = false;
else
check = true;
end
local PlaceHash = MakeHash(PlaceName)
local PlaceData = nil
local RegionData = nil
if Region ~= "" then
RegionData = mw.loadData("Модуль:Statistical/RUS-"..Regions[Region])
PlaceData = RegionData[PlaceHash]
end
if PlaceData == nil then
local NumPage = nil
-- ё = е , так как по соглашению их не различают при сортировке
-- local PlaceEEE = mw.ustring.gsub (PlaceName, "ё", "е")
-- PlaceEEE = mw.ustring.gsub (PlaceEEE, "Ё", "Е")
-- PlaceEEE = mw.ustring.gsub (PlaceEEE, "-", "")
-- do return First_less_Second("Сельское поселение «Село Ильинское» (Малоярославецкий район)", "Сельское поселение Званновский сельсовет"), "Сельское поселение «Село Ильинское» (Малоярославецкий район)"< "Сельское поселение Званновский сельсовет" end
-- do return First_less_Second("Сельское поселение ", "Сельское посе-ление"), "Сельское поселение "< "Сельское посе-ление" end
-- do return First_less_Second("Сельское поселение ", "Сёльс"), "Сельское поселение "< "Сёльс" end
-- 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
-- if NumABC == nil then
-- if check then
-- return 0;
-- else
-- return "#Н/Д"..frame:callParserFunction{name = '#tag:ref', args = {PlaceName .." > Данные не обнаружены. Возможно страница переименовывалась. Проверьте справочник[[Категория:Википедия:Статьи с неправильными параметрами шаблона Население]]"}}
-- end
-- end
-- local ABCPage = mw.loadData("Модуль:Statistical/ABC"..NumABC)
-- if ABCPage[PlaceName] == nil then
-- if check then
-- return 0;
-- else
-- return "#Н/Д"..frame:callParserFunction{name = '#tag:ref', args = {PlaceName .." > Данные не обнаружены. Возможно страница переименовывалась. Проверьте справочник[[Категория:Википедия:Статьи с неправильными параметрами шаблона Население]]"}}
-- end
-- end
NumPage = math.floor((PlaceHash - 1) / 33554432 + 2)
if NumPage == 2 and (PlaceHash - 1) < 16777216 then NumPage = 1 end
if NumPage < 10 then
HashData = mw.loadData("Модуль:Statistical/RUS-00"..NumPage)
else
HashData = mw.loadData("Модуль:Statistical/RUS-0"..NumPage)
end
local RegionPage = HashData[PlaceHash]
if RegionPage ~= nil then
if type(RegionPage) == "table" then RegionPage = RegionPage[PlaceName] end
if RegionPage ~= nil then
RegionData = mw.loadData("Модуль:Statistical/RUS-"..RegionPage)
if RegionData ~= nil then
PlaceData = RegionData[PlaceHash]
end
end
end
-- do return PlaceHash, RegionData end
-- else
-- if RegionData == nil then
end
if PlaceData == nil then
if check then
return 0;
else
return "#Н/Д"..frame:callParserFunction{name = '#tag:ref', args = {PlaceName .." > Данные не обнаружены. Возможно страница переименовывалась. Проверьте справочник[[Категория:Википедия:Статьи с неправильными параметрами шаблона Население]]"}}
end
end
if check then
return 1;
end
local Format = mw.text.trim ( (args[2] or "Таблица"))
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 = RegionData['Источники'][PlaceData[NumRecord][3]][1]
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
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
return p