Toggle menu
14
229
69
27.1K
Kenshi Wiki
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.
Revision as of 01:47, 21 February 2025 by Prd (talk | contribs) (Created page with "require('strict') local p = {} local getArgs = require('Module:Arguments').getArgs -- Units accepted by {{convert}} that come in groups (e.g., "5 ft 6 in") local multiple = {'mich', 'michlk', 'michainlk', 'miyd', 'miydftin', 'mift', 'ydftin', 'ydft', 'ftin', 'footin', 'handin', 'lboz', 'stlb', 'stlboz', 'stlb'} -- Convert unit list to hash local mult_table = {} for _, v in ipairs(multiple) do mult_table[v] = true end -- Function to pull out values and units from num...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

A Lua module that implements {{convinfobox}}: a wrapper around {{convert}} designed for infoboxes.

Usage

{{#invoke:ConvertIB|convert}}

Like {{convinfobox}}, accepts alternating series of pairs of [blank|value], unit . When a unit has a non-blank value, it will get converted to all other units that do have blank values
Accepts all named parameters that {{convert}} does
Accepts groups of multiple units (e.g., "5 ft 6 in") that {{convert}} does

require('strict')
local p = {}
local getArgs = require('Module:Arguments').getArgs

-- Units accepted by {{convert}} that come in groups (e.g., "5 ft 6 in")
local multiple = 
{'mich', 'michlk', 'michainlk', 'miyd', 'miydftin', 'mift', 'ydftin', 'ydft',
'ftin', 'footin', 'handin', 'lboz', 'stlb', 'stlboz', 'stlb'}

-- Convert unit list to hash
local mult_table = {}
for _, v in ipairs(multiple) do
	mult_table[v] = true
end

-- Function to pull out values and units from numeric args
-- Returns:
--   values:  list of numeric values, or "false" if no numeric argument is given
--   units: list of units (str)
--   value: if there is a last numeric value unpaired with a unit, it becomes the precision
--   anyValue: whether there is a non-false value in the values list
local function parseValuesUnits(args)
	local values = {}
	local units = {}
	local indx = 1
	local value = nil
	local anyValue = false
	-- loop through numeric arguments in pairs
	while args[indx] or args[indx+1] do
		value = args[indx]
		anyValue = anyValue or value
		-- if there is a unit, save in output lists
		if args[indx+1] then
			table.insert(values, value or false)
			table.insert(units, args[indx+1])
			value = nil
		end
		indx = indx+2
	end
	return values, units, value, anyValue
end

-- Function to identify multiple units and rewrite them as new input or output groups
-- Args:
--   values, units: numeric values and units, as lists with same length
-- Returns:
--   newValues, newUnits: same lists rewritten
local function parseMultiples(values, units)
	local newValues = {}
	local newUnits = {}
	local i = 1
	-- we will search for multiples with up to 4 entries (depending on length)
	local maxMultiple = math.min(4,#units-1)
	local valueFound = false -- flag to suppress second (and later) input values
	--- Hack for handling "stone": check if only value supplied is "lb"
	local onlyPounds = true
	for i = 1, #units do
		if values[i] and units[i] ~= 'lb' then
			onlyPounds = false
			break
		end
	end
	-- sweep through units
	while i <= #units do
		-- determine index of last possible unit that could contain a multiple
		local last_unit = math.min(i+maxMultiple-1,#units)
		local multipleFound = false
		-- try from longest multiple down to double multiple (prefer longest ones)
		for j = last_unit, i+1, -1 do
			local key = table.concat({unpack(units,i,j)}, '')
			if mult_table[key] then
				-- we found a multiple unit
				multipleFound = true
				-- Hack for "stone": add either 'lb' or multiple unit string to output units
				--    depending on whether 'lb' was the only unit string with a value
				if mw.ustring.sub(key,1,2) == 'st' then
					table.insert(newValues, false)
					table.insert(newUnits, onlyPounds and key or 'lb')
				end
				-- if there are any value in the span of the multiple,
				-- then the multiple is an input
				-- assume all missing values after the first are zero
				local firstValueFound = false
				for k = i, j do
					firstValueFound = not valueFound and (firstValueFound or values[k])
					if firstValueFound then
						table.insert(newValues, values[k] or 0)
						table.insert(newUnits, units[k])
					end
				end
				valueFound = valueFound or firstValueFound
				-- if no values in the span of the multiple,
				-- then the multiple is an output. Insert combined string as output unit
				if not firstValueFound then
					table.insert(newValues, false)
					table.insert(newUnits, key)
				end
				i = j+1
				break
			end
		end
		--- If no multiple unit was found, insert value[i] and unit[i] into rewritten lists
		if not multipleFound then
			if valueFound then
				table.insert(newValues, false) -- skip writing value if it is a duplicate
			else
				table.insert(newValues,values[i])
				valueFound = values[i]
			end
			table.insert(newUnits, units[i])
			i = i+1
		end
	end
	return newValues, newUnits			
end

-- Implement {{convinfobox}}
function p._convert(args)
	-- find all values and units in numeric args (and the precision, if it exists)
	local values, units, precision, anyValue = parseValuesUnits(args)
	-- bail if no values at all
	if not anyValue then
		return nil
	end
	-- rewrite values and units if multiple units are found
	values, units = parseMultiples(values, units)
	-- sort input and outputs into different buckets
	local input_values = {}
	local input_units = {}
	local output_units = {}
	for i = 1, #units do
		if values[i] then
			table.insert(input_values, values[i])
			table.insert(input_units, units[i])
		else
			table.insert(output_units, units[i])
		end
	end
	-- bail if nothing to convert
	if #input_values == 0 or #output_units == 0 then
		return nil
	end
	-- assemble argument list to {{convert}}
	local innerArgs = {}
	-- First, pass all input unit(s)
	for i, v in ipairs(input_values) do
		table.insert(innerArgs,v)
		table.insert(innerArgs,input_units[i])
	end
	-- Then the output unit(s) [concatenated as single argument]
	table.insert(innerArgs,table.concat(output_units,"+"))
	if precision then
		table.insert(innerArgs,precision) -- last non-nil value contains precision
	end
	-- now handle all non-numeric arguments, passing to {{convert}}
	innerArgs.abbr = 'on'  -- abbr=on by default
	for k, v in pairs(args) do
		if not tonumber(k) then
			innerArgs[k] = v
		end
	end
	-- Call {{convert}} with innerArgs
	local frame = mw.getCurrentFrame()
	return frame:expandTemplate{title='Convert', args=innerArgs}
end

function p.convert(frame)
	local args = getArgs(frame)
	return p._convert(args) or ""
end

return p
Contents