Converts numbers to a specified base between 2 and 36, for use in templates such as {{binary}}, {{octal}}, {{hexadecimal}}, etc.

local BaseConvert = require('Module:BaseConvert')
BaseConvert.convert({n = 14600926, base = 16}) -- returns 'DECADE'

Arguments:

  • n - (required) the number to be converted, as a string. It may be a number instead, if the input base is 10.
  • base - (required) the base to which the number should be converted. May be between 2 and 36, inclusive. Defaults to the length of digits parameter below
  • from - the base of the input. Defaults to 10 (or 16 if the input has a leading '0x'). Note that bases other than 10 are not supported if the input has a fractional part.
  • precision - number of digits to be rendered after the radix point. Trailing zeros will be added if needed. If not specified, however many digits are needed will be shown, up to 10.
  • width - minimum number of digits to be rendered before the radix point. Leading zeros will be added if needed.
  • default - Value to return if n is empty or non-numeric. Defaults to the value of n.
  • prefix / suffix - wikitext to add before/after the returned result. Will not be added if n is empty or non-numeric. For example, you might use a prefix of 0x when converting to hex, or a suffix of <sub>8</sub> when converting to octal.
  • digits - Output digits. Defaults to the value of "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".

From templates

แก้ไข

In wikimarkup, this module may be called with a function name ntom, e.g.:

Markup Renders as
{{#invoke:BaseConvert|16to10|  FF  }}

255

{{#invoke:BaseConvert|10to36|500}}

DW

{{#invoke:BaseConvert|10to16|Foo|default=0}}

0

{{#invoke:BaseConvert|convert|n=500|base=16|digits=0123456789กขคฆงจ}}

1จ4

{{#invoke:BaseConvert|convert|n=42|width=5|digits=กขคฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ}}

กกกขก

{{#invoke:BaseConvert|convert2|n=1|digits=กขค}}

{{#invoke:BaseConvert|convert2|n=2|digits=กขค}}

{{#invoke:BaseConvert|convert2|n=3|digits=กขค}}

{{#invoke:BaseConvert|convert2|n=4|digits=กขค}}

กก

{{#invoke:BaseConvert|convert2|n=5|digits=กขค}}

กข

{{#invoke:BaseConvert|convert2|n=6|digits=กขค}}

กค

{{#invoke:BaseConvert|convert2|n=7|digits=กขค}}

ขก

All options above are supported, excluding |base=, |from= and |n= which are set by the mandatory options. You may also call convert which is near-identical to the Lua form above.


local p = {}

local default_digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'

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

function _convert(n, base, from, precision, width, default, prefix, suffix, digits)
    if not digits then digits = default_digits end
    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, mw.ustring.sub(digits, d, d))
    until i == 0
    while #t < (width or 0) do
        table.insert(t, 1, mw.ustring.sub(digits, 1, 1)) 
    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, mw.ustring.sub(digits, 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

    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 _convert2(n, from, precision, default, prefix, suffix, digits)
    local base = mw.ustring.len(digits)
    local max = 1
    local width = 0
    n = tonumber(n, from)
    while n >= max do n = n - max; max = max * base; width = width + 1 end
    local r = _convert(n, base, 10, precision, width, default, prefix, suffix, digits)
    if width == 0 then return mw.ustring.sub(r, 2) end
    return r
end

function _args(frame)
    if frame == mw.getCurrentFrame() then
        return frame.args
    else
        return frame
    end
end

function p.convert(frame)
    -- Allow for invocation via #invoke or directly from another module
    local args = _args(frame)
    
    local n = args.n
    local digits = args.digits
    local base = args.base or digits and mw.ustring.len(digits)
    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, digits)
end

function p.convert2(frame)
    -- Allow for invocation via #invoke or directly from another module
    local args = _args(frame)
    return _convert2(args.n, args.from, args.precision, args.default, args.prefix, args.suffix,
        args.digits or 'a'
    )
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'], args['digits'])
    	end
	end
})

return p