refactor, nothing substantive
|
major refactor and fixes to match template's output
|
||
Line 1: | Line 1: | ||
-- TODO put '0' in front of number like '.123'; remove signs from input uncertainties |
|||
local p = {} |
|||
local getArgs |
local getArgs |
||
local delimit_groups = require('Module:Gapnum').groups |
local delimit_groups = require('Module:Gapnum').groups |
||
Line 6: | Line 5: | ||
-- Specific message for {{Val}} errors |
-- Specific message for {{Val}} errors |
||
local function valerror(msg, nocat) |
local function valerror(msg, nocat) |
||
if is_test_run then -- LATER remove |
|||
return 'Error: "' .. msg .. '"' |
|||
end |
|||
local ret = mw.html.create('strong') |
local ret = mw.html.create('strong') |
||
:addClass('error') |
:addClass('error') |
||
Line 22: | Line 24: | ||
n = mw.ustring.match(tostring(n), '^%(?[±%-%+]?([%d\.]+)%)?$') |
n = mw.ustring.match(tostring(n), '^%(?[±%-%+]?([%d\.]+)%)?$') |
||
return tonumber(n) ~= nil |
return tonumber(n) ~= nil |
||
end |
|||
function p.main(frame) |
|||
if not getArgs then |
|||
getArgs = require('Module:Arguments').getArgs |
|||
end |
|||
local args = getArgs(frame, {wrappers = { 'Template:Val', 'Template:Val/sandboxlua' }}) |
|||
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 (<b>e</b>) is not a valid number.',nocat) |
|||
end |
|||
if args.u and args.ul then |
|||
return valerror('unit (<b>u</b>) and unit with link (<b>ul</b>) are both specified, only one is allowed.',nocat) |
|||
end |
|||
if args.up and args.upl then |
|||
return valerror('unit per (<b>up</b>) and unit per with link (<b>upl</b>) 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, |
|||
link = args.ul ~= nil, |
|||
per = args.upl or args.up, |
|||
per_link = 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 |
end |
||
Line 92: | Line 38: | ||
for item in (text .. ' '):gmatch('(%S[^\n]-)%s%s') do |
for item in (text .. ' '):gmatch('(%S[^\n]-)%s%s') do |
||
if item == 'NOSPACE' then |
if item == 'NOSPACE' then |
||
result.nospace = true |
|||
elseif item == 'ANGLE' then |
|||
result.isangle = true |
|||
result.nospace = true |
result.nospace = true |
||
else |
else |
||
Line 110: | Line 59: | ||
end |
end |
||
end |
end |
||
end |
|||
local function convert_lookup(ucode, options) |
|||
local lookup = require('Module:Convert/sandbox')._unit |
|||
return lookup(ucode, { value = options.value, link = options.want_link }) |
|||
end |
end |
||
Line 117: | Line 71: | ||
get_builtin_unit(ucode, data.builtin_units_long_scale) or |
get_builtin_unit(ucode, data.builtin_units_long_scale) or |
||
get_builtin_unit(ucode, data.builtin_units) |
get_builtin_unit(ucode, data.builtin_units) |
||
local convert_unit = convert_lookup(ucode, { value = value, link = want_link }) |
|||
local lookup = require('Module:Convert/sandbox')._unit |
|||
local convert_unit = lookup(ucode, { value = value, link = want_link }) |
|||
if result then |
if result then |
||
-- Have: result.symbol + result.link + result.nospace |
-- Have: result.symbol + result.link + result.isangle + result.nospace |
||
if want_link then |
if want_link then |
||
result.text = '[[' .. result.link .. '|' .. result.symbol .. ']]' |
result.text = '[[' .. result.link .. '|' .. result.symbol .. ']]' |
||
Line 138: | Line 91: | ||
local function makeunit(ucode, options) |
local function makeunit(ucode, options) |
||
-- Return wikitext, sortkey for the requested unit and options. |
-- Return wikitext, sortkey for the requested unit and options. |
||
-- |
-- TODO The sortkey does not account for any per unit. |
||
local function bracketed(ucode, text) |
local function bracketed(ucode, text) |
||
return ucode:find('[*./]') and '(' .. text .. ')' or text |
return ucode:find('[*./]') and '(' .. text .. ')' or text |
||
Line 153: | Line 106: | ||
text = ' ' .. text |
text = ' ' .. text |
||
end |
end |
||
return text, unit.sortkey |
return { text = text, isangle = unit.isangle, sortkey = unit.sortkey } |
||
end |
end |
||
Line 163: | Line 116: | ||
-- look for + or - preceding the number |
-- look for + or - preceding the number |
||
if n:find('[-+]') then |
if n:find('[-+]') then |
||
prefix, num = |
prefix, num = string.match(n, '([-+])([%d.]+)') |
||
else |
else |
||
num = n |
num = n |
||
Line 171: | Line 124: | ||
-- if there is no decimal part, delimit_groups only returns 1 table |
-- if there is no decimal part, delimit_groups only returns 1 table |
||
local ipart, dpart = delimit_groups(num) |
local ipart, dpart = delimit_groups(num) |
||
-- comma formatting |
|||
if fmt == 'commas' then |
if fmt == 'commas' then |
||
num = table.concat(ipart, ',') |
num = table.concat(ipart, ',') |
||
Line 178: | Line 130: | ||
num = num .. '.' .. dpart |
num = num .. '.' .. dpart |
||
end |
end |
||
-- No special formatting |
|||
elseif fmt == 'none' then |
elseif fmt == 'none' then |
||
-- |
-- TODO Why not use original num? |
||
num = table.concat(ipart) |
num = table.concat(ipart) |
||
if dpart then |
if dpart then |
||
Line 187: | Line 138: | ||
end |
end |
||
else |
else |
||
-- Delimit with a small gap by default. |
|||
num = {} |
num = {} |
||
num[1] = table.remove(ipart, 1) |
num[1] = table.remove(ipart, 1) |
||
Line 205: | Line 157: | ||
-- change hyphen to proper minus sign |
-- change hyphen to proper minus sign |
||
if prefix == '-' then |
if prefix == '-' then |
||
prefix = ' |
prefix = '−' |
||
end |
end |
||
num = prefix .. num |
num = prefix .. num |
||
Line 213: | Line 165: | ||
end |
end |
||
function |
local function _main(number, uncertainty, unit_spec, misc_tbl) |
||
local e_10 = misc_tbl.e |
|||
-- format number |
|||
local fmt = misc_tbl.fmt |
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 |
|||
-- Unit |
-- Unit |
||
local |
local unit_table, sortkey |
||
if |
ifunit_spec.u then |
||
|
unit_table = makeunit(unit_spec.u, { |
||
link = |
link = unit_spec.link, |
||
per = |
per = unit_spec.per, |
||
per_link = |
per_link = unit_spec.per_link, |
||
value = number.n, |
value = (tonumber(number.n) or 1) * (e_10 and 10^e_10 or 1), |
||
longscale = nil, -- TODO set from 'long scale' parameter |
longscale = nil, -- TODO set from 'long scale' parameter |
||
}) |
}) |
||
sortkey = unit_table.sortkey |
|||
else |
|||
sortkey = convert_lookup('dummy', { value = number.n }).sortkey |
|||
end |
end |
||
-- Uncertainty |
-- Uncertainty |
||
local |
local unc_text |
||
local uncU, uncL = uncertainty.upper, uncertainty.lower -- TODO caller should ensure uncU and uncL have no sign |
|||
-- Upper and lower |
|||
-- The entire number needs to be wrapped in parentheses if: |
|||
local uncU, uncL = uncertainty.upper, uncertainty.lower |
|||
-- the exponent parameter (e) is defined AND |
|||
-- Whether or not the entire number needs to be wrapped in parentheses |
|||
-- no lower uncertainty is defined AND |
|||
-- true if: |
|||
|
-- upper uncertainty is defined and contains no parentheses |
||
local paren_wrap = e_10 and (not uncL and (uncU and not uncU:find('%('))) |
|||
---- 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 |
local paren_uncertainty |
||
-- Upper is always used, so look for it first |
|||
if uncU then |
if uncU then |
||
-- Look for lower uncertainty |
|||
if uncL then |
if uncL then |
||
|
local mSu = require('Module:Su')._main -- sup/sub format |
||
uncU = '+' .. delimit(uncU, fmt) .. (uncertainty.upperend or '') |
|||
local mSu = require('Module:Su')._main |
|||
uncL = '−' .. delimit(uncL, fmt) .. (uncertainty.lowerend or '') |
|||
-- Format upper and lower |
|||
if unit_table and unit_table.isangle then |
|||
uncU = delimit(uncU, fmt) |
|||
uncU = uncU .. unit_table.text |
|||
uncL = delimit(uncL, fmt) |
|||
uncL = uncL .. unit_table.text |
|||
-- If no exponent is defined, and there is a unit, add it |
|||
if not e_10 and unit_text then |
|||
uncU = uncU .. unit_text |
|||
uncL = uncL .. unit_text |
|||
end |
end |
||
unc_text = '<span style="margin-left:0.3em;">' .. mSu(uncU, uncL) .. '</span>' |
|||
-- Add the uncertainty suffixes here |
|||
uncU = uncU .. (uncertainty.upperend or '') |
|||
uncL = uncL .. (uncertainty.lowerend or '') |
|||
unc = '<span style="margin-left:0.3em;">' .. mSu(uncU, uncL) .. '</span>' |
|||
else |
else |
||
-- Look for parentheses surrounding upper uncertainty |
-- Look for parentheses surrounding upper uncertainty |
||
|
paren_uncertainty = (uncU:sub(1, 1) == '(' and uncU:sub(-1) == ')') |
||
if paren_uncertainty then |
|||
-- If no parens, use ± |
|||
unc_text = '(' .. delimit(uncU:sub(2, -2), fmt) .. ')' |
|||
if uncU == uncU_n then |
|||
unc = '<span style="margin-left:0.3em;margin-right:0.15em">±</span>' .. delimit(uncU_n, fmt) .. '</span>' |
|||
-- Otherwise tidy the number and put it back in parentheses |
|||
-- Indicate parentheses were used (for later) |
|||
else |
else |
||
|
unc_text = '<span style="margin-left:0.3em;margin-right:0.15em">±</span>' .. delimit(uncU, fmt) .. '</span>' |
||
paren_uncertainty = true |
|||
end |
end |
||
-- Add error suffix |
|||
if uncertainty.errend then |
if uncertainty.errend then |
||
|
unc_text = unc_text .. uncertainty.errend |
||
end |
end |
||
if unit_table and unit_table.isangle then |
|||
-- Add unit if no exponent argument |
|||
unc_text = unc_text .. unit_table.text |
|||
if not e_10 and unit_text then |
|||
unc = unc .. unit_text |
|||
end |
end |
||
end |
end |
||
end |
end |
||
local e_text, n_text |
|||
-- Add unit if no exponent argument and no parentheses for uncertainty |
|||
if number.n then |
|||
if not e_10 and unit_text and not paren_uncertainty then |
|||
|
n_text = delimit(number.n, fmt) .. (number.nend or '') |
||
if not paren_uncertainty and unit_table and unit_table.isangle then |
|||
n_text = n_text .. unit_table.text |
|||
end |
|||
else |
|||
n_text = '' |
|||
e_10 = e_10 or '0' |
|||
end |
end |
||
-- If exponent defined, create 10<sup>e</sup> |
|||
-- Add unit if defined |
|||
if e_10 then |
if e_10 then |
||
|
e_text = '10<sup>' .. delimit(e_10) .. '</sup>' |
||
if n then |
ifnumber.n then |
||
|
e_text = '<span style="margin-left:0.25em;margin-right:0.15em">×</span>' .. e_text |
||
end |
|||
if unit_text then |
|||
e_10 = e_10 .. unit_text |
|||
end |
end |
||
else |
else |
||
|
e_text = '' |
||
end |
end |
||
return table.concat({ |
return table.concat({ |
||
'<span class="nowrap">', |
'<span class="nowrap">', |
||
misc_tbl. |
misc_tbl.prefix or '', |
||
paren_wrap and '(' or '', |
paren_wrap and '(' or '', |
||
n_text, |
|||
n or '', -- number |
|||
unc_text or '', |
|||
unc or '', -- uncertainties |
|||
paren_wrap and ')' or '', |
paren_wrap and ')' or '', |
||
e_text, |
|||
e_10, -- suffix -- 10^e if needed |
|||
(unit_table and not unit_table.isangle) and unit_table.text or '', |
|||
misc_tbl.suf or '', |
|||
misc_tbl.suffix or '', |
|||
'</span>' |
'</span>' |
||
}) |
}) |
||
end |
end |
||
local function main(frame) |
|||
return p |
|||
if not getArgs then |
|||
getArgs = require('Module:Arguments').getArgs |
|||
end |
|||
local args = getArgs(frame, {wrappers = { 'Template:Val', 'Template:Val/sandboxlua' }}) |
|||
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 |
|||
if args.e and not validnumber(args.e) then |
|||
return valerror('exponent argument (<b>e</b>) is not a valid number.',nocat) |
|||
end |
|||
if args.u and args.ul then |
|||
return valerror('unit (<b>u</b>) and unit with link (<b>ul</b>) are both specified, only one is allowed.',nocat) |
|||
end |
|||
if args.up and args.upl then |
|||
return valerror('unit per (<b>up</b>) and unit per with link (<b>upl</b>) 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 unit_spec = { |
|||
u = args.ul or args.u, |
|||
link = args.ul ~= nil, |
|||
per = args.upl or args.up, |
|||
per_link = args.upl ~= nil, |
|||
} |
|||
local misc_tbl = { |
|||
e = args.e, |
|||
prefix = args.p, |
|||
suffix = args.s, |
|||
fmt = args.fmt or '', |
|||
nocat = args.nocategory, |
|||
} |
|||
return _main(number, uncertainty, unit_spec, misc_tbl) |
|||
end |
|||
return { main = main, _main = _main } |
This Lua module is used on approximately 39,000 pages and changes may be widely noticed. Test changes in the module's /sandboxor/testcases subpages, or in your own module sandbox. Consider discussing changes on the talk page before implementing them. |
This module implements {{Val}}.
The following modules are developed:
Use {{val/sandbox}} for testing, for example:
{{val/sandbox|1234.5678|(23)|u=cm}}
→ 1234.5678(23) cm{{val/sandbox|1234.5678|1.23|u=cm}}
→ 1234.5678±1.23 cm{{val/sandbox|1234.5678|1.23|4.56|u=cm}}
→ 1234.5678+1.23{{val/sandbox|1234.5678|e=3|u=cm}}
→ 1234.5678×103 cm{{val/sandbox|1234.5678|(23)|e=3|u=cm}}
→ 1234.5678(23)×103 cm{{val/sandbox|1234.5678|1.23|e=3|u=cm}}
→ (1234.5678±1.23)×103 cm{{val/sandbox|1234.5678|1.23|4.56|e=3|u=cm}}
→ 1234.5678+1.23{{val/sandbox|1234.5678|1.23|4.56|e=3|u=cm|end=$|+errend=U$|-errend=L$}}
→ 1234.5678$+1.23U${{val/sandbox|1234.5678|(23)|u=deg}}
→ 1234.5678(23)°{{val/sandbox|1234.5678|1.23|u=deg}}
→ 1234.5678°±1.23°{{val/sandbox|1234.5678|1.23|4.56|u=deg}}
→ 1234.5678°+1.23°{{val/sandbox|1234.5678|e=3|u=deg}}
→ 1234.5678°×103{{val/sandbox|1234.5678|(23)|e=3|u=deg}}
→ 1234.5678(23)°×103{{val/sandbox|1234.5678|1.23|e=3|u=deg}}
→ (1234.5678°±1.23°)×103{{val/sandbox|1234.5678|1.23|4.56|e=3|u=deg}}
→ 1234.5678°+1.23°{{val/sandbox|1234.5678|1.23|4.56|e=3|u=deg|end=$|+errend=U$|-errend=L$}}
→ 1234.5678$°+1.23U$°
-- TODO put '0' in front of number like '.123'; remove signs from input uncertainties
local getArgs
local delimit_groups = require('Module:Gapnum').groups
-- Specific message for {{Val}} errors
local function valerror(msg, nocat)
if is_test_run then -- LATER remove
return 'Error: "' .. msg .. '"'
end
local ret = mw.html.create('strong')
:addClass('error')
:wikitext('Error in {{Val}}: ' .. 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('[[Category:Pages with incorrect formatting templates use]]')
end
return tostring(ret)
end
-- true/false whether or not the string is a valid number
-- ignores parentheses and parity symbolts
local 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
local function get_builtin_unit(unitcode, definitions)
-- Return table of information for the specified built-in unit, or nil if not known.
-- Each defined unit code must be followed by two spaces (not tab characters).
local _, pos = definitions:find('\n' .. unitcode .. ' ', 1, true)
if pos then
local endline = definitions:find('\n', pos, true)
if endline then
local result = {}
local n = 0
local text = definitions:sub(pos, endline - 1)
for item in (text .. ' '):gmatch('(%S[^\n]-)%s%s') do
if item == 'NOSPACE' then
result.nospace = true
elseif item == 'ANGLE' then
result.isangle = true
result.nospace = true
else
n = n + 1
if n == 1 then
result.symbol = item
elseif n == 2 then
result.link = item
else
break
end
end
end
if n == 2 then
return result
end
-- Ignore invalid definition, treating it as a comment.
end
end
end
local function convert_lookup(ucode, options)
local lookup = require('Module:Convert/sandbox')._unit
return lookup(ucode, { value = options.value, link = options.want_link })
end
local function get_unit(ucode, value, want_link, want_longscale)
local data = mw.loadData('Module:Val/units')
local result = want_longscale and
get_builtin_unit(ucode, data.builtin_units_long_scale) or
get_builtin_unit(ucode, data.builtin_units)
local convert_unit = convert_lookup(ucode, { value = value, link = want_link })
if result then
-- Have: result.symbol + result.link + result.isangle + result.nospace
if want_link then
result.text = '[[' .. result.link .. '|' .. result.symbol .. ']]'
else
result.text = result.symbol
end
result.sortkey = convert_unit.sortkey
else
result = {
text = convert_unit.text,
sortkey = convert_unit.sortkey,
}
end
return result
end
local function makeunit(ucode, options)
-- Return wikitext, sortkey for the requested unit and options.
-- TODO The sortkey does not account for any per unit.
local function bracketed(ucode, text)
return ucode:find('[*./]') and '(' .. text .. ')' or text
end
options = options or {}
local unit = get_unit(ucode, options.value, options.link, options.longscale)
local text = unit.text
local percode = options.per
if percode then
local perunit = get_unit(percode, 0, options.per_link, options.longscale)
text = bracketed(ucode, text) .. '/' .. bracketed(percode, perunit.text)
end
if not unit.nospace then
text = ' ' .. text
end
return { text = text, isangle = unit.isangle, sortkey = unit.sortkey }
end
-- TODO: Add other format options
local 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 = string.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)
if fmt == 'commas' then
num = table.concat(ipart, ',')
if dpart then
dpart = table.concat(dpart)
num = num .. '.' .. dpart
end
elseif fmt == 'none' then
-- TODO Why not use original num?
num = table.concat(ipart)
if dpart then
dpart = table.concat(dpart)
num = num .. '.' .. dpart
end
else
-- Delimit with a small gap by default.
num = {}
num[1] = table.remove(ipart, 1)
for _, v in ipairs(ipart) do
table.insert(num, '<span style="margin-left:.25em">' .. v .. '</span>')
end
if dpart then
table.insert(num, '.' .. table.remove(dpart, 1))
for _, v in ipairs(dpart) do
table.insert(num, '<span style="margin-left:.25em">' .. v .. '</span>')
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 = '−'
end
num = prefix .. num
end
return tostring(num)
end
local function _main(number, uncertainty, unit_spec, misc_tbl)
local e_10 = misc_tbl.e
local fmt = misc_tbl.fmt
-- Unit
local unit_table, sortkey
if unit_spec.u then
unit_table = makeunit(unit_spec.u, {
link = unit_spec.link,
per = unit_spec.per,
per_link = unit_spec.per_link,
value = (tonumber(number.n) or 1) * (e_10 and 10^e_10 or 1),
longscale = nil, -- TODO set from 'long scale' parameter
})
sortkey = unit_table.sortkey
else
sortkey = convert_lookup('dummy', { value = number.n }).sortkey
end
-- Uncertainty
local unc_text
local uncU, uncL = uncertainty.upper, uncertainty.lower -- TODO caller should ensure uncU and uncL have no sign
-- The entire number needs to be wrapped in parentheses if:
-- the exponent parameter (e) is defined AND
-- no lower uncertainty is defined AND
-- upper uncertainty is defined and contains no parentheses
local paren_wrap = e_10 and (not uncL and (uncU and not uncU:find('%(')))
local paren_uncertainty
if uncU then
if uncL then
local mSu = require('Module:Su')._main -- sup/sub format
uncU = '+' .. delimit(uncU, fmt) .. (uncertainty.upperend or '')
uncL = '−' .. delimit(uncL, fmt) .. (uncertainty.lowerend or '')
if unit_table and unit_table.isangle then
uncU = uncU .. unit_table.text
uncL = uncL .. unit_table.text
end
unc_text = '<span style="margin-left:0.3em;">' .. mSu(uncU, uncL) .. '</span>'
else
-- Look for parentheses surrounding upper uncertainty
paren_uncertainty = (uncU:sub(1, 1) == '(' and uncU:sub(-1) == ')')
if paren_uncertainty then
unc_text = '(' .. delimit(uncU:sub(2, -2), fmt) .. ')'
else
unc_text = '<span style="margin-left:0.3em;margin-right:0.15em">±</span>' .. delimit(uncU, fmt) .. '</span>'
end
if uncertainty.errend then
unc_text = unc_text .. uncertainty.errend
end
if unit_table and unit_table.isangle then
unc_text = unc_text .. unit_table.text
end
end
end
local e_text, n_text
if number.n then
n_text = delimit(number.n, fmt) .. (number.nend or '')
if not paren_uncertainty and unit_table and unit_table.isangle then
n_text = n_text .. unit_table.text
end
else
n_text = ''
e_10 = e_10 or '0'
end
if e_10 then
e_text = '10<sup>' .. delimit(e_10) .. '</sup>'
if number.n then
e_text = '<span style="margin-left:0.25em;margin-right:0.15em">×</span>' .. e_text
end
else
e_text = ''
end
return table.concat({
'<span class="nowrap">',
misc_tbl.prefix or '',
paren_wrap and '(' or '',
n_text,
unc_text or '',
paren_wrap and ')' or '',
e_text,
(unit_table and not unit_table.isangle) and unit_table.text or '',
misc_tbl.suffix or '',
'</span>'
})
end
local function main(frame)
if not getArgs then
getArgs = require('Module:Arguments').getArgs
end
local args = getArgs(frame, {wrappers = { 'Template:Val', 'Template:Val/sandboxlua' }})
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
if args.e and not validnumber(args.e) then
return valerror('exponent argument (<b>e</b>) is not a valid number.',nocat)
end
if args.u and args.ul then
return valerror('unit (<b>u</b>) and unit with link (<b>ul</b>) are both specified, only one is allowed.',nocat)
end
if args.up and args.upl then
return valerror('unit per (<b>up</b>) and unit per with link (<b>upl</b>) 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 unit_spec = {
u = args.ul or args.u,
link = args.ul ~= nil,
per = args.upl or args.up,
per_link = args.upl ~= nil,
}
local misc_tbl = {
e = args.e,
prefix = args.p,
suffix = args.s,
fmt = args.fmt or '',
nocat = args.nocategory,
}
return _main(number, uncertainty, unit_spec, misc_tbl)
end
return { main = main, _main = _main }