Модуль:Statistical
Поделись знанием:
Для документации этого модуля может быть создана страница Модуль:Statistical/doc
local p = {} 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 hash = LimitDouble(hash + mw.ustring.codepoint(PlaceName, currentIndex + 1)) tmp = bit32.bxor(shl(mw.ustring.codepoint(PlaceName, currentIndex + 2), 11), hash) hash = bit32.bxor(shl(hash, 16), tmp) hash = LimitDouble(hash + shr(hash, 11)) currentIndex = currentIndex + 2 numberOfLoops = numberOfLoops - 1 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)) 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 = mw.ustring.char(0160), 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 GetHashData(PlaceHash) local 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 return HashData[PlaceHash]; 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 function FormatH() return PlaceHash end 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 RegionPage = GetHashData(PlaceHash) if RegionPage ~= nil then if type(tonumber(RegionPage)) == "number" then PlaceHash=tonumber(RegionPage) RegionPage = GetHashData(PlaceHash) end 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 end local Format = mw.text.trim ( (args[2] or "Таблица")) if PlaceData == nil then if check then return 0; elseif Format == 'Хеш' or Format == 'х' then return FormatH() else return "#Н/Д"..frame:callParserFunction{name = '#tag:ref', args = {PlaceName .." > Данные не обнаружены. Возможно страница переименовывалась. Проверьте справочник".. ((args.nocat and "") or "[[Категория:Википедия:Статьи с неправильными параметрами шаблона Население]]")}} end end if check then return 1; 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 = RegionData['Источники'][PlaceData[NumRecord][3]][1] Source2 = PlaceData[NumRecord][3] else Source1 = PlaceData[NumRecord][3] Source2 = "" end if string.find(Source1, "https?://")==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 = 320 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, ['colors'] = "#B0C4DE", ['x legends'] = tempLegend, ['group names'] = 'Численность населения', ['default color'] = '#1E90FF' } local cframe = mw.getCurrentFrame(); return barChart(cframe:newChild{ title=cframe.title, args = Diagram}) else -- Формироание HTML-таблицы local HTML = mw.html.create('table') local MaxData if args['Столбцов'] then Column = tonumber(args['Столбцов']) else Column = 7 end if Column > LastRecord then Column = LastRecord end if args['Оформление'] ~= nil then HTML:attr('class', args['Оформление']) else HTML:attr('class', 'standard') 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