|
|
(4 intermediate revisions by 3 users not shown) |
Line 3: |
Line 3: |
| local digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' | | local digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' |
|
| |
|
| 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 |
|
| |
|
| 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 = tostring(n) |
|
| |
| -- 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,
| | -- strip off any leading '0x' (unless x is a valid digit in the input base) |
| -- because tonumber doesn't support negative numbers in non-10 bases.
| | from = tonumber(from) |
| local sign = ''
| | if not from or from < 34 then |
| local c
| | local c |
| n, c = n:gsub('^-', '')
| | n, c = n:gsub('^(-?)0[Xx]', '%1') |
| if c > 0 then sign = '-' end
| | if c > 0 and not from then from = 16 end |
|
| | 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 = {}
| | -- check for a negative sign. Do this while the input is still in string form, |
| repeat
| | -- because tonumber doesn't support negative numbers in non-10 bases. |
| local d = (i % base) + 1
| | local sign = '' |
| i = math.floor(i / base)
| | local c |
| table.insert(t, 1, digits:sub(d, d))
| | n, c = n:gsub('^-', '') |
| until i == 0
| | if c > 0 then sign = '-' end |
| 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, '')
| | -- replace any full-width Unicode characters in the string with their ASCII equivalents |
|
| | n = normalizeFullWidthChars(n) |
| -- remove trailing zeros if not needed
| | |
| if not precision then
| | -- handle scientific notation with whitespace around the 'e' e.g. '5 e7' |
| fracPart = fracPart:gsub('0*$', '')
| | n = n:gsub('%s*[eE]%s*', 'e') |
| end
| | |
|
| | from = from or 10 |
| -- add the radix point if needed
| | local num = tonumber(n, from) |
| if #fracPart > 0 then
| | base = tonumber(base) |
| fracPart = '.' .. fracPart
| | precision = tonumber(precision) |
| end
| | width = tonumber(width) |
|
| | |
| return (prefix or '') .. sign .. intPart .. fracPart .. (suffix or '')
| | 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 = 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 | | 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 |
| | |
| | setmetatable(p, { |
| | __index = function(t, k) |
| | local from, base = k:match('^([0-9]+)to([0-9]+)$') |
| | if not from then return nil end |
| | return function(frame) |
| | local 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 | | return p |