Module:Gapnum: Difference between revisions

From Zoophilia Wiki
Jump to navigationJump to search
meta>Jackmcbarn
args come already preprocessed
Ookami (talk | contribs)
m 73 revisions imported
 
(40 intermediate revisions by 4 users not shown)
Line 7: Line 7:
getArgs = require('Module:Arguments').getArgs
getArgs = require('Module:Arguments').getArgs
end
end
local args = getArgs(frame, {wrappers = 'Template:Gapnum'})
local args = getArgs(frame, {wrappers = 'Template:Gapnum'})
local gap = args.gap or '0.25em'
local n = args[1]
 
if not n then
error('Parameter 1 is required')
elseif not tonumber(n) and not tonumber(n, 36) then -- Validates any number with base ≤ 36
error('Unable to convert "' .. args[1] .. '" to a number')
end
 
local gap = args.gap
local precision = tonumber(args.prec)
 
return p.gaps(n,{gap=gap,prec=precision})
end
 
-- Not named p._main so that it has a better function name when required by Module:Val
function p.gaps(n,tbl)
local nstr = tostring(n)
if not tbl then
tbl = {}
end
local gap = tbl.gap or '.25em'
 
local int_part, frac_part = p.groups(n,tbl.prec)
 
local ret = mw.html.create('span')
:css('white-space','nowrap')
-- No gap necessary on first group
:wikitext(table.remove(int_part,1))
 
-- Build int part
for _, v in ipairs(int_part) do
ret:tag('span')
:css('margin-left',gap)
:wikitext(v)
end


local ret_string = '<span style="white-space:nowrap">'
if frac_part then
-- The first group after the decimal shouldn't have a gap
ret:wikitext('.' .. table.remove(frac_part,1))
-- Build frac part
for _, v in ipairs(frac_part) do
ret:tag('span')
:css('margin-left',gap)
:wikitext(v)
end
end


local number = tonumber(args[1])
return ret
end
if not number then
 
return 'Error: parameter 1 did not parse as a number.'
-- Creates tables where each element is a different group of the number
function p.groups(num,precision)
local nstr = tostring(num)
if not precision then
precision = -1
end
end


-- Split number into 2 parts: integer part and decimal part
local decimalloc = nstr:find('.', 1, true)
local int_part = math.floor(number)
local int_part, frac_part
int_part = tostring(int_part)
if decimalloc == nil then
-- Using substrings instead of math to avoid rounding errors
int_part = nstr
local frac_part = tostring(number):sub(int_part:len()+2)
else
int_part = nstr:sub(1, decimalloc-1)
-- If the frac_part is empty, reinterpret it as 0
frac_part = nstr:sub(decimalloc + 1)
if frac_part:len() == 0 then
-- Explicit call required to make it a number
frac_part = tonumber(0)
end
end
-- only define ret_i as an empty table, let ret_d stay nil
local int_string = ''
local ret_i,ret_d = {}
-- Loop to handle most of the groupings; from right to left, so that if a group has
-- Loop to handle most of the groupings; from right to left, so that if a group has less than 3 members, it will be the first group
-- less than 3 members, it will be the first group
while int_part:len() > 3 do
while int_part:len() >= 3 do
-- Insert in first spot, since we're moving backwards
int_string = '<span style="margin-left:'..gap..';">'..int_part:sub(-3)..'</span>'..int_string
table.insert(ret_i,1,int_part:sub(-3))
int_part = int_part:sub(1,-4)
int_part = int_part:sub(1,-4)
end
end
-- handle any left over numbers
-- handle any left over numbers
if int_part:len() > 0 then
if int_part:len() > 0 then
int_string = '<span style="margin-left:'..gap..';">'..int_part..'</span>'..int_string
table.insert(ret_i,1,int_part)
end
end
 
ret_string = ret_string..int_string
if precision ~= 0 and frac_part then
ret_d = {}
local precision = tonumber(args.prec) or -1
if precision == -1 then
-- if the precision is NOT 0 (a whole number) and the decimal part is NOT empty (i.e. 0)
precision = frac_part:len()
if precision ~=0 and frac_part ~= 0 then
end
frac_part = tostring(frac_part)
local frac_string = '.'
-- Reduce the length of the string if required precision is less than actual precision
-- Reduce the length of the string if required precision is less than actual precision
-- OR
-- OR
-- Increase it (by adding 0s) if the required precision is more than actual
-- Increase it (by adding 0s) if the required precision is more than actual
if precision > 0 then
local offset = precision - frac_part:len()
if precision < frac_part:len() then
if offset < 0 then
frac_part = frac_part:sub(1,precision)
frac_part = frac_part:sub(1,precision)
elseif precision > frac_part:len() then
elseif offset > 0 then
while frac_part:len() < precision do
frac_part = frac_part .. string.rep('0', offset)
frac_part = frac_part..'0'
end
end
end
end
 
-- The first group after the decimal shouldn't have a gap between the decimal
-- Allow groups of 3 or 2 (3 first)
if frac_part:len() >= 3 then
for v in string.gmatch(frac_part,'%d%d%d?') do
frac_string = frac_string..frac_part:sub(1,3)
table.insert(ret_d,v)
frac_part = frac_part:sub(4)
else
frac_string = frac_string..frac_part
frac_part = ''
end
end
-- Preference for groups of 4 instead of groups of 1 at the end
-- Loop to handle most of the groupings; from left to right, so that if a group has
if #frac_part % 3 == 1 then
-- less than 3 members, it will be the last group
if frac_part:len() == 1 then
while frac_part:len() >= 3 do
ret_d = {frac_part}
frac_string = frac_string..'<span style="margin-left:'..gap..';">'..frac_part:sub(1,3)..'</span>'
else
frac_part = frac_part:sub(4)
local last_g = ret_d[#ret_d] or ''
end
last_g = last_g..frac_part:sub(-1)
ret_d[#ret_d] = last_g
-- Handle any left over numbers
end
if frac_part:len() > 0 then
frac_string = frac_string..'<span style="margin-left:'..gap..';">'..frac_part..'</span>'
end
end
ret_string = ret_string..frac_string
end
end
-- Closing span tag
ret_string = ret_string..'</span>'


return ret_string
return ret_i,ret_d
end
end


return p
return p

Latest revision as of 13:41, 3 September 2020

Documentation for this module may be created at Module:Gapnum/doc

local p = {}

local getArgs

function p.main(frame)
	if not getArgs then
		getArgs = require('Module:Arguments').getArgs
	end

	local args = getArgs(frame, {wrappers = 'Template:Gapnum'})
	local n = args[1]

	if not n then
		error('Parameter 1 is required')
	elseif not tonumber(n) and not tonumber(n, 36) then -- Validates any number with base ≤ 36
		error('Unable to convert "' .. args[1] .. '" to a number')
	end

	local gap = args.gap
	local precision = tonumber(args.prec)

	return p.gaps(n,{gap=gap,prec=precision})
end

-- Not named p._main so that it has a better function name when required by Module:Val
function p.gaps(n,tbl)
	local nstr = tostring(n)
	if not tbl then
		tbl = {}
	end
	local gap = tbl.gap or '.25em'

	local int_part, frac_part = p.groups(n,tbl.prec)

	local ret = mw.html.create('span')
							:css('white-space','nowrap')
							-- No gap necessary on first group
							:wikitext(table.remove(int_part,1))

	-- Build int part
	for _, v in ipairs(int_part) do
		ret:tag('span')
				:css('margin-left',gap)
				:wikitext(v)
	end

	if frac_part then
		-- The first group after the decimal shouldn't have a gap
		ret:wikitext('.' .. table.remove(frac_part,1))
		-- Build frac part
		for _, v in ipairs(frac_part) do
			ret:tag('span')
					:css('margin-left',gap)
					:wikitext(v)
		end
	end

	return ret
end

-- Creates tables where each element is a different group of the number
function p.groups(num,precision)
	local nstr = tostring(num)
	if not precision then
		precision = -1
	end

	local decimalloc = nstr:find('.', 1, true)
	local int_part, frac_part
	if decimalloc == nil then
		int_part = nstr
	else
		int_part = nstr:sub(1, decimalloc-1)
		frac_part = nstr:sub(decimalloc + 1)
	end
	-- only define ret_i as an empty table, let ret_d stay nil
	local ret_i,ret_d = {}
	-- Loop to handle most of the groupings; from right to left, so that if a group has less than 3 members, it will be the first group
	while int_part:len() > 3 do
		-- Insert in first spot, since we're moving backwards
		table.insert(ret_i,1,int_part:sub(-3))
		int_part = int_part:sub(1,-4)
	end
	-- handle any left over numbers
	if int_part:len() > 0 then
		table.insert(ret_i,1,int_part)
	end

	if precision ~= 0 and frac_part then
		ret_d = {}
		if precision == -1 then
			precision = frac_part:len()
		end
		-- Reduce the length of the string if required precision is less than actual precision
		-- OR
		-- Increase it (by adding 0s) if the required precision is more than actual
		local offset = precision - frac_part:len()
		if offset < 0 then
			frac_part = frac_part:sub(1,precision)
		elseif offset > 0 then
			frac_part = frac_part .. string.rep('0', offset)
		end

		-- Allow groups of 3 or 2 (3 first)
		for v in string.gmatch(frac_part,'%d%d%d?') do
			table.insert(ret_d,v)
		end
		-- Preference for groups of 4 instead of groups of 1 at the end
		if #frac_part % 3 == 1 then
			if frac_part:len() == 1 then
				ret_d = {frac_part}
			else
				local last_g = ret_d[#ret_d] or ''
				last_g = last_g..frac_part:sub(-1)
				ret_d[#ret_d] = last_g
			end
		end
	end

	return ret_i,ret_d
end

return p