Module:Xconv
Lua
CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules
The main function in this module is "xconv
", for Template:{{Xconv}}
LUA performs conversions very differently:
- from hexadecimal to decimal:
tonumber(HEXNUM, 16)
- from decimal to hexadecimal:
string.format('%X', DECNUM)
, orstring.format('%04X', DECNUM)
to specify a minimum number of hexadecimal digits (using right-padding with zeroes)
An example can be performed with the functions h2d
and d2h
{{#invoke:Xconv|h2d|50FFFF2FFFF0}}<sub>d</sub>
gives 89060428218352d{{#invoke:Xconv|d2h|4096}}<sub>h</sub>
will give 1000h{{#invoke:Xconv|d2h|255|4}}<sub>h</sub>
will give 00FFh
Code
local p = {}
local min = math.min
local max = math.max
local floor = math.floor
local format = string.format
local sub = mw.ustring.sub
local gsub = mw.ustring.gsub
local upper = mw.ustring.upper
local lower = mw.ustring.lower
local trim = mw.text.trim
local split = mw.text.split
--------------------------------------------------------------------------------
-- Main function: for numeric check
-- Hex-conversion and selection of conversion mode
function p.xconv(frame)
-- local lprm = frame -- local parms
local gprm = frame.args -- global parms
-- local pprm = mw.getCurrentFrame():getParent().args
local inpt = {}
for i = 1, 3 do
local v = gprm[i] or ''
gprm[i] = v
v = trim(v)
inpt[i] = upper(v)
inpt[i + 3] = v
end
local err = '' -- detected errors
local fna = '' -- assumed mode
local fno = '' -- output mode
local fnr = '' -- 'r' for rgb() color, or '#' for hex color
local sp0 = '(' -- or 'rgb('
local sp1 = ',' -- or '%,'
local sp3 = ')' -- or '%)'
if inpt[3] ~= '' then
fna = '4' -- three parms: 4a (or 3c)
inpt[1] = inpt[1] .. '/' .. inpt[2] .. '/' .. inpt[3]
else
if inpt[2] ~= '' then -- only one param
inpt[5] = sub(inpt[5], 'r', '')
if #inpt[2] > #inpt[5] then
sp0 = 'rgb('
end
if inpt[5] == 'n' then
fna = 'n' -- 1: d2h
elseif inpt[5] == 'h' then
fna = 'h' -- 2: h2d
elseif inpt[5] == 'o' then
fno = 'o' -- 3: rgb(3ab or 4bcd)
elseif inpt[5] == 'no' or inpt[5] == 'on' then
fna = 'n' -- 1: d2h, or 4bcd
fno = 'o' -- edit
elseif inpt[5] == 's' or inpt[5] == 'ns' or inpt[5] == 'sn' then
fna = 'n' -- 4bcd
fno = 's' -- shorten
elseif inpt[5] == 'ho' or inpt[5] == 'oh' then
fna = 'h' -- 2: h2d, or 3ab
fno = 'o' -- edit
elseif inpt[5] == '%' then
fna = 'h' -- rgb(3ab)
sp1 = '%,'
sp3 = '%)'
else
err = err .. '4' -- parm2 is wrong function code
end
end
if inpt[1] ~= '' then
if lower(sub(inpt[4], 1, 4)) == 'rgb(' then
fna = 'n' -- 4cd
fnr = 'r' -- rgb
inpt[1] = sub(inpt[1], 4, #inpt[1])
end
end
end
local rgp = '' -- empty or 3 rgb % signs
local num = '' -- number bytes
local hex = '' -- number + hex bytes
local nhs = '' -- number + hex bytes + separator slashes
local pts = 0 -- numbers of decimal points
for i = 1, #inpt[1] do
local tmp = sub(inpt[1], i, i)
-- if tmp >= '0' and tmp <= "9" then
if tmp == '0' or tmp == '1' or tmp == '2' or tmp == '3' or tmp == '4'
or tmp == '5' or tmp == '6' or tmp == '7' or tmp == '8' or tmp == '9' then
num = num .. tmp
hex = hex .. tmp
nhs = nhs .. tmp
elseif tmp == '.' then -- fnc = 4d
if pts == 0 then
num = num .. '.'
hex = hex .. '.'
nhs = nhs .. '.'
pts = 1
else
err = err .. '5' -- more than one point
end
-- elseif tmp >= 'A' and tmp <= 'F' then
elseif tmp == 'A' or tmp == 'B' or tmp == 'C' or tmp == 'D' or tmp == 'E' or tmp == 'F' then
hex = hex .. tmp
nhs = nhs .. tmp
elseif tmp == ' ' or tmp == ',' or tmp == '-' or tmp == '/' then
if sub(nhs, #nhs, #nhs) ~= '/' then
nhs = nhs .. '/'
pts = 0 -- reset for next item
elseif sub(inpt[1], i-1, i) ~= ', ' then
err = err .. '3' -- more than one delimiter in sequ.
end
elseif tmp == '%' then -- fnc = 4d
if i < #inpt[1] then
inpt[7] = sub(inpt[1], i + 1, i + 1)
end
if inpt[7] == ',' or inpt[7] == ')' then
inpt[7] = '/'
end
if i < #inpt[1] and inpt[7] ~= '/' then
nhs = nhs .. '/'
pts = 0 -- reset for next item
end
rgp = rgp .. '%' -- 3 times
if #rgp > 3 then
err = err .. '6' -- % sign error
end
elseif i == 1 then
if tmp == '(' then
fnr = 'r'
elseif tmp == '#' then
fnr = '#'
else
err = err .. '2' -- '(' or '#' occurs at non-first position
end
elseif i == #inpt[1] then
if tmp == ')' and fnr == 'r' then
tmp = tmp
end -- ignore end-')' when 'r'
elseif tmp ~= '' then -- ignore spacing separator
err = err .. '1' -- character not identifiable
end -- if
end -- for
local dect = {0, 0, 0}
local fnc = '' -- conversion mode
if fnr == '#' and err == '' then
if #hex == 3 then -- 3a
inpt[6] = sub(hex, 3, 3) .. sub(hex, 3, 3)
inpt[5] = sub(hex, 2, 2) .. sub(hex, 2, 2)
inpt[4] = sub(hex, 1, 1) .. sub(hex, 1, 1)
elseif #hex == 6 then
inpt[6] = sub(hex, 5, 6)
inpt[5] = sub(hex, 3, 4)
inpt[4] = sub(hex, 1, 2)
else
err = err .. '#'
end -- neither 6 nor 3
for i = 1, 3 do
dect[i] = tonumber(inpt[i + 3], 16)
if sp3 == '%)' then
dect[i] = floor(dect[i] / 255 * 1000) / 1000
end
end -- for
fnc = '3' -- 3
elseif #num < #hex or fna == 'h' then
if #nhs == #hex + 2 then -- 3bC
local sndt = split(nhs, '/')
for i = 1, 3 do
dect[i] = tonumber(sndt[i], 16)
if dect[i] > 255 then
err = err .. '8'
else
if sp3 == '%)' then
dect[i] = floor(dect[i] / 255 * 1000) / 1000
end
end
end -- for
fnc = '3' -- 3
else
if fnr ~= '#' then
dect[1] = tonumber(hex, 16)
fnc = '2' -- 2
end
end
else -- #num == #hex (a numeric value, and not 'h')
if #nhs == #hex then
fnc = '1' -- 1
inpt[1] = format('%X', num)
else -- #nhs == #hex + 2 == #num + 2 (3 num values) -- 4A, 4b or 4c, 4d
dect = split(nhs, '/')
fnc = '4' -- 4
for i = 1, 3 do
if rgp == '' then
if tonumber(dect[i]) > 255 then -- 4A, 4b, 4c
err = err .. '8'
end
inpt[i] = format('%02X', dect[i])
else -- rgp = '%%%' -- 4d
if rgp ~= '%%%' then
err = err .. '7' -- (6) not three '%'
end
if tonumber(dect[i]) > 100 then -- 4d
err = err .. '9'
end
dect[i + 3] = floor(dect[i] * 255 / 100 + .5)
inpt[i] = format('%02X', dect[i + 3])
end
end -- for
if fno == 's' -- shortening required ?
and sub(inpt[1], 1, 1) == sub(inpt[1], 2, 2)
and sub(inpt[2], 1, 1) == sub(inpt[2], 2, 2)
and sub(inpt[3], 1, 1) == sub(inpt[3], 2, 2) then
inpt[1] = sub(inpt[1], 1, 1)
inpt[2] = sub(inpt[2], 1, 1)
inpt[3] = sub(inpt[3], 1, 1)
end -- shorten #rrggbb to #rgb
end -- if #nhs
end -- if #num
--[[
err: string, indicates parsing errors that may have been encountered:
'1': non-numeric or non-hexadecimal characters
'2': '(' or '#' occurs at non-first position
'3': separator (or separator combination}
'4': parm2 input wrong function code
'5': decimal point error
'6': % sign error
'7': not three '%'
'8': not all decimal color codes are < 256
'9': more than 100%
inpt: table of 6 strings, contains 3 trimmed parameters after their uppercase versions
dect: table of 3 decimal values
num: string, contains all numeric bytes
hex: string, contains all numeric plus hexadecimal bytes
nhs: string, contains all numeric plus hexadecimal bytes plus inbetween slashes
rgp: string, may contain three '%' from rgb() notation
--]]
--[[ Only for tests:
if fnc == '4' then
return 'err=' .. err .. ', fn=' .. fna .. fno .. fnr .. fnc
.. ', '.. inpt[1]
.. ', '.. num .. '~' .. hex .. '~' .. nhs
.. ', '.. tostring(dect[1]) .. "'" .. tostring(dect[2]) .. "'" .. tostring(dect[3])
.. ', ' .. rgp
.. ', ' .. inpt[1] .. '"' .. inpt[2] .. '"' .. inpt[3]
else
return 'err=' .. err .. ', fn=' .. fna .. fno .. fnr .. fnc
.. ', '.. inpt[1]
.. ', '.. num .. '~' .. hex .. '~' .. nhs
.. ', '.. tostring(dect[1]) .. "'" .. tostring(dect[2]) .. "'" .. tostring(dect[3])
.. ', '.. rgp
end
--]]
if err ~= '' then
return 'Error = ' .. err
elseif fnc == '1' then
return inpt[1] .. '<sub>h</sub>'
elseif fnc == '2' then
return tostring(dect[1]) .. '<sub>d</sub>'
elseif fnc == '3' then
return sp0 .. dect[1] .. sp1 .. dect[2] .. sp1 .. dect[3] .. sp3
elseif fnc == '4' then
return '#'-- leading '#' HTML-escaped against MediaWiki reinterpretation
.. inpt[1] .. inpt[2] .. inpt[3]
end
end -- function xconv
--------------------------------------------------------------------------------
-- Convert hexadecimal value (from 0 to FFFFFFFFFFF) to decimal value(from 0 to 17592186044415)
function p.h2d(frame)
local gprm = frame.args -- global parms
return tonumber(gprm[1], 16) or ''
end -- function h2d
--------------------------------------------------------------------------------
-- Convert decimal value (from 0 to 17592186044415) to hexadecimal value(from 0 to FFFFFFFFFFF)
function p.d2h(frame)
local gprm = frame.args -- global parms
local value = tonumber(gprm[1]) or 0
local width = min(max(tonumber(gprm[2]) or 1, 1), 16)
return format('%0' .. tostring(width) .. 'X', value)
end -- function d2h
--------------------------------------------------------------------------------
return p