Módulo:Gb
Revisão de 19h35min de 26 de setembro de 2025 por GhoulBlack (discussão | contribs)
A documentação para este módulo pode ser criada em Módulo:Gb/doc
local p = {}
-- === Utilidades ===
local function trim(s)
if type(s) ~= "string" then
return s
end
return mw.text.trim(s)
end
local function split_list(s)
-- Tenta primeiro por ';' (recomendado quando usar vírgula decimal).
if s:find(";") then
local t = {}
for part in mw.text.gsplit(s, ";", true) do
table.insert(t, part)
end
return t
end
-- Caso não haja ';', separa por ',' (útil se números usam ponto decimal).
local t = {}
for part in mw.text.gsplit(s, ",", true) do
table.insert(t, part)
end
return t
end
local function parse_number(token)
if type(token) ~= "string" then
return nil
end
token = trim(token)
if token == "" then
return nil
end
-- Remove espaços
token = token:gsub("%s+", "")
-- Heurística pt-BR:
-- 1) Se tiver vírgula e ponto, assume '.' como milhar e ',' como decimal
-- Ex.: "1.234,56" -> "1234.56"
if token:find(",") and token:find("%.") then
token = token:gsub("%.", "") -- tira milhares
token = token:gsub(",", ".") -- vírgula -> ponto decimal
-- 2) Se só tiver vírgula, assume vírgula decimal
elseif token:find(",") then
token = token:gsub(",", ".")
-- 3) Se só tiver ponto, deixa como está (ponto decimal)
end
local n = tonumber(token)
return n
end
local function collect_numbers(frame)
local args = frame:getParent() and frame:getParent().args or frame.args
local nums = {}
-- 1) Lista em 'valores='
local lista = args.valores or args.lista
if lista and trim(lista) ~= "" then
for _, part in ipairs(split_list(lista)) do
local n = parse_number(part)
if n then
table.insert(nums, n)
end
end
end
-- 2) Parâmetros posicionais 1,2,3,...
local i = 1
while true do
local v = args[i]
if v == nil then
break
end
v = trim(v)
if v and v ~= "" then
-- Pode ser lista dentro do posicional
local parts = split_list(v)
for _, part in ipairs(parts) do
local n = parse_number(part)
if n then
table.insert(nums, n)
end
end
end
i = i + 1
end
return nums
end
local function round(n, casas)
if not casas or casas == "" then
return n
end
casas = tonumber(casas) or 0
local mult = 10 ^ casas
if n >= 0 then
return math.floor(n * mult + 0.5) / mult
else
return math.ceil(n * mult - 0.5) / mult
end
end
local function format_number(n, casas, formato)
n = round(n, casas)
if formato == "pt" then
-- Formata com vírgula decimal e ponto de milhar
local s = string.format("%." .. tostring(tonumber(casas) or 0) .. "f", n)
-- s usa ponto decimal; converter para pt-BR
local inteiro, frac = s:match("^(-?%d+)%.(%d+)$")
if not inteiro then
inteiro = s
frac = nil
end
-- insere pontos nos milhares
local k
local sign = ""
if inteiro:sub(1, 1) == "-" then
sign = "-"
inteiro = inteiro:sub(2)
end
while true do
inteiro, k = inteiro:gsub("^(-?%d+)(%d%d%d)", "%1.%2")
if k == 0 then
break
end
end
if frac then
return sign .. inteiro .. "," .. frac
else
return sign .. inteiro
end
else
-- "en" ou padrão: ponto decimal, sem milhar
local casasN = tonumber(casas) or 0
return string.format("%." .. tostring(casasN) .. "f", n)
end
end
local function compute(nums, op)
if #nums == 0 then
return nil
end
if op == "soma" or op == "sum" then
local s = 0
for _, v in ipairs(nums) do
s = s + v
end
return s
elseif op == "media" or op == "média" or op == "avg" then
local s = 0
for _, v in ipairs(nums) do
s = s + v
end
return s / #nums
elseif op == "min" or op == "mín" then
local m = nums[1]
for i = 2, #nums do
if nums[i] < m then
m = nums[i]
end
end
return m
elseif op == "max" then
local m = nums[1]
for i = 2, #nums do
if nums[i] > m then
m = nums[i]
end
end
return m
elseif op == "contar" or op == "count" then
return #nums
else
-- padrão: soma
local s = 0
for _, v in ipairs(nums) do
s = s + v
end
return s
end
end
-- === Interface pública ===
function p.calc(frame)
local args = frame:getParent() and frame:getParent().args or frame.args
local op = (args.op or args.operacao or args.operacao or "soma"):lower()
local casas = args.casas or args.decimais or 2
local formato = (args.formato or args.locale or "pt"):lower() -- "pt" ou "en"
local nums = collect_numbers(frame)
local result = compute(nums, op)
if result == nil then
return "—" -- sem dados
end
return format_number(result, casas, formato)
end
return p