Difference between revisions of "Module:BaseConvert"

From blackwiki
Jump to navigation Jump to search
blackwiki>Toohool
(fix handling of string input)
blackwiki>Toohool
(add ability to specify a default return value)
Line 11: Line 11:
 
-- width - minimum number of digits to be rendered before the radix point.
 
-- width - minimum number of digits to be rendered before the radix point.
 
--  Leading zeros will be added if needed.
 
--  Leading zeros will be added if needed.
 +
-- default - Value to return if n is empty or non-numeric. Defaults to the
 +
--  value of n.
 
--
 
--
  
Line 17: Line 19:
 
local digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
 
local digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  
−
function p._convert(n, base, from, precision, width)
+
function p._convert(n, base, from, precision, width, default)
 
     n = '' .. n  -- convert to a string
 
     n = '' .. n  -- convert to a string
 
      
 
      
Line 41: Line 43:
 
     width = tonumber(width)
 
     width = tonumber(width)
 
      
 
      
−
     if not num or not base then return 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)
Line 92: Line 94:
 
     local precision = frame.args.precision
 
     local precision = frame.args.precision
 
     local width = frame.args.width
 
     local width = frame.args.width
−
     return p._convert(n, base, from, precision, width)
+
    local default = frame.args.default
 +
     return p._convert(n, base, from, precision, width, default)
 
end
 
end
  
 
return p
 
return p

Revision as of 04:51, 24 February 2013

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

Example usage:

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.
  • 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.

--
-- Converts numbers to a specified base between 2 and 36, for use in
-- templates such as {{binary}}, {{octal}}, {{hexadecimal}}, etc.
--
-- 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.
--

local p = {}

local digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'

function p._convert(n, base, from, precision, width, default)
    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
    
    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

    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 sign .. intPart .. fracPart
end

function p.convert(frame)
    local n = frame.args.n
    local base = frame.args.base
    local from = frame.args.from
    local precision = frame.args.precision
    local width = frame.args.width
    local default = frame.args.default
    return p._convert(n, base, from, precision, width, default)
end

return p