Module:Val

local p = {} local getArgs local delimit_groups = require('Module:Gapnum').groups

function p.main(frame) if not getArgs then getArgs = require('Module:Arguments').getArgs end -- local args = getArgs(frame, {wrappers = 'Template:Val'}) local args = getArgs(frame, {wrappers = 'Template:Val/sandboxlua'}) -- TODO restore to 'Template:Val' if  or  invoke Module:Val local number = {n=args[1], nend=args['end']} local nocat = args.nocategory -- Error checking if args[1] and not validnumber(args[1]) then return valerror('first argument is not a valid number.',nocat) end if args[2] and not validnumber(args[2]) then return valerror('second argument is not a valid number.',nocat) end if args[3] and not validnumber(args[3]) then return valerror('third argument is not a valid number.',nocat) end -- Negative third param if args[3] and (not mw.ustring.find(args[3],'[−%-]') or mw.ustring.find(args[3],'^%D0$')) then return valerror('third argument is not negative.',nocat) end if args.e and not validnumber(args.e) then return valerror('exponent argument (e) is not a valid number.',nocat) end if args.u and args.ul then return valerror('unit (u) and units with link (ul) are both specified, only one is allowed.',nocat) end if args.up and args.upl then return valerror('unit per (up) and units per with link (upl) are both specified, only one is allowed.',nocat) end

-- Group arguments into related categories and unpack when needed local uncertainty = {upper=args[2], lower=args[3], errend=args.errend, upperend=args['+errend'], lowerend=args['-errend']} local u_tbl = {u=args.ul or args.u, ul=args.ul ~= nil, p=args.upl or args.up, pl=args.upl ~= nil} local misc_tbl = {e=args.e, pre=args.p, suf=args.s, fmt=args.fmt or '', nocat=args.nocategory} return p._main(number,uncertainty,u_tbl,misc_tbl) end

function p._main(number,uncertainty,u_tbl,misc_tbl) -- format number local fmt = misc_tbl.fmt local n	if number.n then n = delimit(number.n,fmt) end local e_10 = misc_tbl.e

-- number suffix if n and number.nend then n = n..number.nend end

-- If units are defined, load the unit submodule to create a string if u_tbl.u then local makeunit = require('Module:Val/units') units = makeunit(u_tbl.u,{						link=u_tbl.ul,						per=u_tbl.p,						per_link=u_tbl.pl}) end

-- Uncertainty local unc -- Upper and lower local uncU, uncL = uncertainty.upper, uncertainty.lower -- Whether or not the entire number needs to be wrapped in parentheses -- true if: the expontent parameter (e) is defined AND no lower uncertainty is defined AND upper uncertainty is defined and contains no parentheses local paren_wrap = misc_tbl.e and (not uncL and (uncU and not uncU:find('%(')))

-- boolean to be defined and used later local paren_uncertainty -- Upper is always used, so look for it first if uncU then -- Look for lower uncertainty if uncL then -- Load the sup/sub module local mSu = require('Module:Su')._main -- Format upper and lower uncU = delimit(uncU,fmt) uncL = delimit(uncL,fmt) -- If no exponent is defined, and there are units, add them if not e_10 and units then uncU = uncU..units uncL = uncL..units end -- Add the uncertainty suffixes here uncU = uncU..(uncertainty.upperend or '') uncL = uncL..(uncertainty.lowerend or '')

unc = ' '..mSu(uncU,uncL)..' ' else -- Look for parentheses surrounding upper uncertainty local uncU_n = mw.ustring.match(uncU,('%((.+)%)')) or uncU -- If no parens, use ± if uncU == uncU_n then unc = ' ± '..delimit(uncU_n,fmt)..' ' -- Otherwise tidy the number and put it back in parentheses -- Indicate parentheses were used (for later) else unc = '('..delimit(uncU_n,fmt)..')' paren_uncertainty = true end -- Add error suffix if uncertainty.errend then unc = unc..uncertainty.errend end -- Add units if no exponent argument if not e_10 and units then unc = unc..units end end end -- Add units if no exponent argument and no parentheses for uncertainty if not e_10 and units and not paren_uncertainty then n = (n or '')..units end -- If exponent defined, create 10e -- Add units if they're defined if e_10 then e_10 = '10'..delimit(misc_tbl.e)..'' if n then e_10 = ' × '..e_10 end if units then e_10 = e_10..units end else e_10 = '' end -- Table to concat in order of what goes where local ret = table.concat({				' ',				-- prefix				misc_tbl.pre or ,				-- opening parenthesis if needed				paren_wrap and '(' or , -- number n or '', -- uncertainties unc or '', -- closes parenthesis if needed paren_wrap and ')' or ,				-- 10^e if needed				e_10,				-- suffix				misc_tbl.suf or ,				' '			}) return ret end

-- TODO: Add other format options function delimit(n,fmt) local prefix,num if not fmt then fmt = '' end fmt = fmt:lower -- look for + or - preceding the number if n:find('[-+]') then prefix,num = mw.ustring.match(n,'([-+])([%d.]+)') else num = n	end

-- integer and decimal parts of number -- if there is no decimal part, delimit_groups only returns 1 table local ipart, dpart = delimit_groups(num) -- comma formatting if fmt == 'commas' then num = table.concat(ipart,',') if dpart then dpart = table.concat(dpart) num = num..'.'..dpart end -- No special formatting elseif fmt == 'none' then -- default to delimiting with .25em spaces num = table.concat(ipart) if dpart then dpart = table.concat(dpart) num = num..'.'..dpart end else num = {} num[1] = table.remove(ipart,1) for _, v in ipairs(ipart) do			table.insert(num,' '..v..' ') end if dpart then table.insert(num,'.'..table.remove(dpart,1)) for _, v in ipairs(dpart) do				table.insert(num,' '..v..' ') end end num = table.concat(num) end

-- add prefix back if it had one if prefix then -- change hyphen to proper minus sign if prefix == '-' then prefix = '&minus;' end num = prefix..num end

return tostring(num) end

-- Specific message for errors function valerror(msg,nocat) local ret = mw.html.create('strong') :addClass('error') :wikitext('Error in &#123;&#123;Val&#125;&#125;: '..msg) -- Not in talk, user, user_talk, or wikipedia_talk if not nocat and not mw.title.getCurrentTitle:inNamespaces(1,2,3,5) then ret:wikitext('') end return tostring(ret) end

-- true/false whether or not the string is a valid number -- ignores parentheses and parity symbolts function validnumber(n) -- Look for a number that may be surrounded by parentheses or may have +/- n = mw.ustring.match(tostring(n),'^%(?[±%-%+]?([%d\.]+)%)?$') return tonumber(n) ~= nil end

return p