Module:BaseConvert

From Lojban
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

local p = {}

local 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)

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

return p