Jump to content

Module:BaseConvert/sandbox: Difference between revisions

From Wikipedia, the free encyclopedia
Content deleted Content added
remove trailing whitespace
use tabs for indents as is customary
Line 4: Line 4:


local function normalizeFullWidthChars(s)
local function normalizeFullWidthChars(s)
return mw.ustring.gsub(s, '[!-~]', function(s)
return mw.ustring.gsub(s, '[!-~]', function(s)
return mw.ustring.char(mw.ustring.codepoint(s, 1) - 0xFEE0)
return mw.ustring.char(mw.ustring.codepoint(s, 1) - 0xFEE0)
end)
end)
end
end


local function _convert(n, base, from, precision, width, default, prefix, suffix)
local function _convert(n, base, from, precision, width, default, prefix, suffix)
n = '' .. n -- convert to a string
n = '' .. n -- convert to a string


-- strip off any leading '0x' (unless x is a valid digit in the input base)
-- strip off any leading '0x' (unless x is a valid digit in the input base)
from = tonumber(from)
from = tonumber(from)
if not from or from < 34 then
if not from or from < 34 then
local c
local c
n, c = n:gsub('^(-?)0[Xx]', '%1')
n, c = n:gsub('^(-?)0[Xx]', '%1')
if c > 0 and not from then from = 16 end
if c > 0 and not from then from = 16 end
end
end


-- check for a negative sign. Do this while the input is still in string form,
-- check for a negative sign. Do this while the input is still in string form,
-- because tonumber doesn't support negative numbers in non-10 bases.
-- because tonumber doesn't support negative numbers in non-10 bases.
local sign = ''
local sign = ''
local c
local c
n, c = n:gsub('^-', '')
n, c = n:gsub('^-', '')
if c > 0 then sign = '-' end
if c > 0 then sign = '-' end


-- replace any full-width Unicode characters in the string with their ASCII equivalents
-- replace any full-width Unicode characters in the string with their ASCII equivalents
n = normalizeFullWidthChars(n)
n = normalizeFullWidthChars(n)


-- handle scientific notation with whitespace around the 'e' e.g. '5 e7'
-- handle scientific notation with whitespace around the 'e' e.g. '5 e7'
n = n:gsub('%s*[eE]%s*', 'e')
n = n:gsub('%s*[eE]%s*', 'e')


from = from or 10
from = from or 10
local num = tonumber(n, from)
local num = tonumber(n, from)
base = tonumber(base)
base = tonumber(base)
precision = tonumber(precision)
precision = tonumber(precision)
width = tonumber(width)
width = tonumber(width)


if not num or not base then return default or n end
if not num or not base then return default or n end


local i, f = math.modf(num)
local i, f = math.modf(num)


local t = {}
local t = {}
repeat
repeat
local d = (i % base) + 1
local d = (i % base) + 1
i = math.floor(i / base)
i = math.floor(i / base)
table.insert(t, 1, digits:sub(d, d))
table.insert(t, 1, digits:sub(d, d))
until i == 0
until i == 0
while #t < (width or 0) do
while #t < (width or 0) do
table.insert(t, 1, '0')
table.insert(t, 1, '0')
end
end
local intPart = table.concat(t, '')
local intPart = table.concat(t, '')


-- compute the fractional part
-- compute the fractional part
local tf = {}
local tf = {}
while f > 0 and #tf < (precision or 10) do
while f > 0 and #tf < (precision or 10) do
f = f * base
f = f * base
i, f = math.modf(f)
i, f = math.modf(f)
table.insert(tf, digits:sub(i + 1, i + 1))
table.insert(tf, digits:sub(i + 1, i + 1))
end
end


-- add trailing zeros if needed
-- add trailing zeros if needed
if precision and #tf < precision then
if precision and #tf < precision then
for i = 1, precision - #tf do
for i = 1, precision - #tf do
table.insert(tf, '0')
table.insert(tf, '0')
end
end
end
end


local fracPart
local fracPart
fracPart = table.concat(tf, '')
fracPart = table.concat(tf, '')


-- remove trailing zeros if not needed
-- remove trailing zeros if not needed
if not precision then
if not precision then
fracPart = fracPart:gsub('0*$', '')
fracPart = fracPart:gsub('0*$', '')
end
end


-- add the radix point if needed
-- add the radix point if needed
if #fracPart > 0 then
if #fracPart > 0 then
fracPart = '.' .. fracPart
fracPart = '.' .. fracPart
end
end


return (prefix or '') .. sign .. intPart .. fracPart .. (suffix or '')
return (prefix or '') .. sign .. intPart .. fracPart .. (suffix or '')
end
end


function p.convert(frame)
function p.convert(frame)
-- Allow for invocation via #invoke or directly from another module
-- Allow for invocation via #invoke or directly from another module
local args
local args
if frame == mw.getCurrentFrame() then
if frame == mw.getCurrentFrame() then
args = frame.args
args = frame.args
else
else
args = frame
args = frame
end
end


local n = args.n
local n = args.n
local base = args.base
local base = args.base
local from = args.from
local from = args.from
local precision = args.precision
local precision = args.precision
local width = args.width
local width = args.width
local default = args.default
local default = args.default
local prefix = args.prefix
local prefix = args.prefix
local suffix = args.suffix
local suffix = args.suffix
return _convert(n, base, from, precision, width, default, prefix, suffix)
return _convert(n, base, from, precision, width, default, prefix, suffix)
end
end


Line 111: Line 111:
return function(frame)
return function(frame)
args = frame.args
args = frame.args
return _convert(mw.text.trim(args[1]), base, from, args['precision'], args['width'],
return _convert(mw.text.trim(args[1]), base, from, args['precision'], args['width'],
args['default'], args['prefix'], args['suffix'])
args['default'], args['prefix'], args['suffix'])
end
end
end
end
})
})

Revision as of 06:56, 12 April 2022

local p = {}

local digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'

local function normalizeFullWidthChars(s)
	return mw.ustring.gsub(s, '[!-~]', function(s)
		return mw.ustring.char(mw.ustring.codepoint(s, 1) - 0xFEE0)
	end)
end

local function _convert(n, base, from, precision, width, default, prefix, suffix)
	n = '' .. n   -- convert to a string

	-- strip off any leading '0x' (unless x is a valid digit in the input base)
	from = tonumber(from)
	if not from or from < 34 then
		local c
		n, c = n:gsub('^(-?)0[Xx]', '%1')
		if c > 0 and not from then from = 16 end
	end

	-- check for a negative sign. Do this while the input is still in string form,
	-- because tonumber doesn't support negative numbers in non-10 bases.
	local sign = ''
	local c
	n, c = n:gsub('^-', '')
	if c > 0 then sign = '-' end

	-- replace any full-width Unicode characters in the string with their ASCII equivalents
	n = normalizeFullWidthChars(n)

	-- handle scientific notation with whitespace around the 'e' e.g. '5 e7'
	n = n:gsub('%s*[eE]%s*', 'e')

	from = from or 10
	local num = tonumber(n, from)
	base = tonumber(base)
	precision = tonumber(precision)
	width = tonumber(width)

	if not num or not base then return default or n end

	local i, f = math.modf(num)

	local t = {}
	repeat
		local d = (i % base) + 1
		i = math.floor(i / base)
		table.insert(t, 1, digits:sub(d, d))
	until i == 0
	while #t < (width or 0) do
		table.insert(t, 1, '0')
	end
	local intPart = table.concat(t, '')

	-- compute the fractional part
	local tf = {}
	while f > 0 and #tf < (precision or 10) do
		f = f * base
		i, f = math.modf(f)
		table.insert(tf, digits:sub(i + 1, i + 1))
	end

	-- add trailing zeros if needed
	if precision and #tf < precision then
		for i = 1, precision - #tf do
			table.insert(tf, '0')
		end
	end

	local fracPart
	fracPart = table.concat(tf, '')

	-- remove trailing zeros if not needed
	if not precision then
		fracPart = fracPart:gsub('0*$', '')
	end

	-- add the radix point if needed
	if #fracPart > 0 then
		fracPart = '.' .. fracPart
	end

	return (prefix or '') .. sign .. intPart .. fracPart .. (suffix or '')
end

function p.convert(frame)
	-- Allow for invocation via #invoke or directly from another module
	local args
	if frame == mw.getCurrentFrame() then
		args = frame.args
	else
		args = frame
	end

	local n = args.n
	local base = args.base
	local from = args.from
	local precision = args.precision
	local width = args.width
	local default = args.default
	local prefix = args.prefix
	local suffix = args.suffix
	return _convert(n, base, from, precision, width, default, prefix, suffix)
end

setmetatable(p, {
	__index = function(t, k)
		from, base = k:match('^([0-9]+)to([0-9]+)$')
		if not from then return nil end
		return function(frame)
			args = frame.args
			return _convert(mw.text.trim(args[1]), base, from, args['precision'], args['width'],
				args['default'], args['prefix'], args['suffix'])
		end
	end
})

return p