Content deleted Content added
fixes for default rounding with composite input units |
process input/output in order left-to-right so left is linked; avoid overlinking, including of spelled numbers; boost default precision if input uses a fraction |
||
Line 7:
local format = string.format
local log10 = math.log10
local function boolean(text)
-- Return true if text represents a "true" option value.
if text then
text = text:lower()
if text == '1' or text == 'y' or text == 'yes' or text == 'true' then
return true
end
end
end
-- Configuration options to keep magic values in one ___location.
local numdot, numsep, maxsigfig, warnings
-- The conversion data and message text are defined in separate modules.
-- To allow easy comparison between "require" and "loadData", a config option
Line 23 ⟶ 33:
numsep = args.numsep or ',' -- thousands separator for numbers (',', '.', '')
maxsigfig = args.maxsigfig or 14 -- maximum number of significant figures
warnings = boolean(args.warnings) -- true if want warnings for invalid options
-- Scribunto sets the global variable 'mw'.
-- A testing program can set the global variable 'is_test_run'.
Line 175 ⟶ 186:
elseif key == 'link' then
value = self.name1
elseif key == '
value = false
else
Line 217 ⟶ 228:
elseif key == 'link' then
value = self.name1
elseif key == '
value = false
else
Line 247 ⟶ 258:
local unit1, unit2 = per[1], per[2]
value = (unit1 and unit1.scale or 1) / unit2.scale
elseif key == '
value = false
else
Line 584 ⟶ 595:
local function format_number(parms, show, exponent, isnegative)
-- Return t where t is a table with
-- show = wikitext formatted to display implied value
-- is_scientific = true if show uses scientific notation
Line 757 ⟶ 768:
-- * If negative, a Unicode minus is used; otherwise the sign is
-- '+' (if the input text used '+'), or is '' (if no sign in input).
text = strip(text)
if text == nil or text == '' then return false, { missing[which] } end
Line 765 ⟶ 774:
clean = text
else
clean = text:gsub('[' .. numsep .. ']', '') -- use '[
end
-- Remove any sign character (assuming a number starts with '.' or a digit).
Line 874 ⟶ 883:
return nil
end
end
preunit2 = preunit2 or ''
local trim2 = strip(preunit2)
if trim1 == '' and trim2 == '' then
end
if trim1 ~= '+' then
end
if trim2 == ' ' then -- trick to make preunit2 empty
elseif trim2 == '' then
elseif trim2 ~= '+' then
end
return preunit1, preunit2
Line 922 ⟶ 931:
-- If enabled, add a warning that will be displayed after the convert result.
-- Currently, only the first warning is displayed.
if
if parms.warnings == nil then
parms.warnings = message({ mcode, text })
Line 1,174 ⟶ 1,183:
local integer, dot, fraction, expstr = inclean:match('^(%d*)([' .. numdot .. ']?)(%d*)(.*)')
local e = expstr:sub(1, 1)
local boost = 0 -- can increase default precision
if e == 'e' or e == 'E' then
exponent = tonumber(expstr:sub(2))
elseif expstr:find('/', 1, true) then
boost = 1 -- any input fraction is regarded as one extra digit of precision
end
if dot == '' then
Line 1,229 ⟶ 1,241:
minprec = extra.minprec or minprec
end
return math.max(floor(prec + adjust + boost), minprec)
end
Line 1,407 ⟶ 1,419:
end
else
precision = -precision -- #digits to zero (in addition to any digits after dot)
local shift = 10 ^ precision
show = format('%.0f', outvalue/shift)
Line 1,415 ⟶ 1,427:
end
end
if (show == '1' or show:match('^1%.0*$') ~= nil) and not isnegative then
-- Use match because on some systems 0.99999999999999999 is 1.0.
Line 1,523 ⟶ 1,532:
end
local linked_pages -- to record linked pages so will not link to the same page more than once
local function make_link(link, id, link_key)
-- Return wikilink "[[link|id]]", possibly abbreviated as in examples:
-- [[Mile|mile]] --> [[mile]]
-- [[Mile|miles]] --> [[mile]]s
-- However, just id is returned if:
-- * no link given (so caller does not need to check if a link was defined); or
-- * link has previously been used during the current convert (to avoid overlinking).
-- Linking with a unit uses the unit table as the link key, which fails to detect
-- overlinking for conversions like (each links "mile" twice):
-- {{convert|1|impgal/mi|USgal/mi|lk=on}}
-- {{convert|1|l/km|impgal/mi USgal/mi|lk=on}}
link_key = link_key or link -- use key if given (the key, but not the link, may be known when need to cancel a link record)
if link == nil or link == '' or linked_pages[link_key] then
return id
end
linked_pages[link_key] = true
local l = link:sub(1, 1):lower() .. link:sub(2)
if link == id or l == id then
Line 1,540 ⟶ 1,563:
-- Return final unit id (symbol or name), optionally with a wikilink,
-- and update unit_table.sep if required.
-- key_id is one of: 'symbol', 'sym_us', 'name1', 'name1_us', 'name2', 'name2_us'.
local abbr_on = (key_id == 'symbol' or key_id == 'sym_us')
if abbr_on and want_link then
Line 1,613 ⟶ 1,627:
local link = link_exceptions[unit_table.symbol] or unit_table.link
if link then
local before = ''
local i = unit_table.customary
if i == 1 and unit_table.sp_us then
Line 1,622 ⟶ 1,637:
local customary = customary_units[i]
if customary then
local pertext
if id:sub(1, 1) == '/' then
-- Want unit "/USgal" to display as "/U.S. gal", not "U.S. /gal".
pertext = '/'
id = id:sub(2)
elseif id:sub(1, 4) == 'per ' then
-- Similarly want "per U.S. gallon", not "U.S. per gallon" (but in practice this is unlikely to be used).
pertext = 'per '
id = id:sub(5)
else
pertext = ''
end
-- Omit any "US"/"U.S."/"imp"/"imperial" from start of id since that will be inserted.
local removes = (i < 3) and { 'US ', 'US ', 'U.S. ', 'U.S. ' } or { 'imp ', 'imp ', 'imperial ' }
Line 1,631 ⟶ 1,658:
end
end
before = pertext .. make_link(customary.link, customary[1]) .. ' '
end
id =
end
end
Line 1,758 ⟶ 1,784:
local lk = parms.lk
if lk == 'on' or lk == inout then
number_id = make_link(engscale
else
number_id = engscale[1]
end
-- WP:NUMERAL recommends " " in values like "12 million".
info.show = info.show .. (parms.opt_adjectival and '-' or ' ') .. number_id
end
end
Line 1,788 ⟶ 1,815:
end
local id1, want_name = make_id(parms, 1, first_unit)
local sep = first_unit.sep -- separator between value and unit, set by make_id
local preunit = parms.preunit1
if preunit then
Line 1,840 ⟶ 1,867:
local result = prefix .. valinfo[1].show
if range then
result = range_text(range, want_name, parms, result, prefix2 .. valinfo[2].show)
end
return preunit .. result
Line 1,866 ⟶ 1,894:
mos = (abbr == 'mos')
if not (mos or (parms.is_range_x and not want_name)) then
linked_pages[first_unit
end
end
Line 1,873 ⟶ 1,901:
if mos and was_hyphenated then
mos = false -- suppress repeat of unit in a range
if linked_pages[first_unit
linked_pages[first_unit
id = make_id(parms, 2, first_unit)
extra = hyphenated_maybe(parms, want_name, sep, id, 'in')
Line 1,938 ⟶ 1,966:
if range then
if not (parms.is_range_x and not want_name) then
linked_pages[out_current
end
end
Line 2,043 ⟶ 2,071:
local link = out_current.link
if link then
id = make_link(link, id, out_current)
end
end
Line 2,074 ⟶ 2,102:
-- Return true, s where s = final wikitext result,
-- or return false, t where t is an error message table.
linked_pages = {}
local success, out_unit_table
local invalue1 = in_unit_table.valinfo[1].value
Line 2,086 ⟶ 2,115:
return false, { 'cvt_mismatch', in_unit_table.utype, out_unit_table.utype }
end
local
local parts = {}
for part = 1, 2 do
-- The LHS (parts[1]) is normally the input, but is the output if flipped.
-- Process LHS first so it will be linked, if wanted.
-- Linking to the same item is suppressed in the RHS to avoid overlinking.
if (part == 1 and not flipped) or (part == 2 and flipped) then
parts[part] = process_input(parms, in_unit_table)
else
local outputs = {}
local combos -- nil (for 'ft' or 'ftin'), or table of unit tables (for 'm ft')
if out_unit_table.multiple == nil then -- nil ('ft' or 'm ft'), or table of factors ('ftin')
combos = out_unit_table.combination
end
local imax = combos and #combos or 1 -- 1 (single unit) or number of unit tables
for i = 1, imax do
local success, item
local out_current = combos and combos[i] or out_unit_table
out_current.inout = 'out'
if out_current.multiple == nil then
success, item = make_output_single(parms, in_unit_table, out_current)
else
success, item = make_output_multiple(parms, in_unit_table, out_current)
end
if not success then return false, item end
table.insert(outputs, item)
end
parts[part] = parms.opt_input_unit_only and '' or table.concat(outputs, '; ')
end
end
if parms.opt_sortable then
end
local wikitext
if parms.table_joins then
wikitext = parms.table_joins[1] ..
else
wikitext =
end
if parms.warnings then
|