Module:Gapnum

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, 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