模組:NumberUtil

本页使用了标题或全文手工转换
被永久保护的模块
维基百科,自由的百科全书
文档图示 模块文档[查看] [编辑] [历史] [清除缓存]

本模組包含了一些處理數字或數值相關的函數。

local p={}
local lib_arg={}
local lib_var={}
local yesno = {}
local lib_tempPar = {}

function p.foreachNumber(frame)
	local args, working_frame
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        if lib_arg.getArgs == nil then lib_arg = require('Module:Arguments') end
        args = lib_arg.getArgs(frame, {parentFirst=true})
        working_frame = frame
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
        working_frame = mw.getCurrentFrame()
        if type(args) ~= type({}) then args = {frame} end
    end
    local input_article = args[1] or args['1'] or ''
    local input_calc = args[2] or args['2'] or '$1'
    local pattern = '#expr:' .. mw.ustring.gsub(input_calc,'%%(%d+)','%%%%%1') .. '}}'
    if mw.isSubsting() then pattern = 'safesubst:' .. pattern end
    pattern = '{{' .. pattern
    pattern = mw.ustring.gsub(pattern,'%$','(%%1)')
    local result = mw.ustring.gsub(input_article,'(%-?[%d%.]+)',pattern)
	return working_frame:preprocess( result )
end 

function p.forrangeNumber(frame)
	if lib_var._arg_process == nil then lib_var = require('Module:Var') end
	local args, working_frame = lib_var._arg_process(frame)
	local expr=args[4] or args['4'] or 'x'
	local var_name=args[5] or args['5'] or 'x'
	local var_str=args[6] or args['6'] or 'x'
	var_str = mw.ustring.gsub(var_str,"%%","%%%%");
	expr = mw.ustring.gsub(expr,"%a+",function(str)
		if str==var_name then return "("..var_str..")" end 
	end)
	expr = mw.ustring.gsub(expr,"[質质素][數数]","primeIndexAtModuleFactorization")
	local output_str=args[1] or args['1'] or '$1,'
	local start_n = tonumber(args[2] or args['2'] or args.min or '1')or 1
	local end_n = tonumber(args[3] or args['3'] or args.max or '10')or 10
	local math_lib = math
	local tonumber_func = tonumber

    if args.template then
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
		if yesno(args.template or 'no') then
			return p.templateSequence(frame)
		end
    end
	if args.class then
		local comp_number;
		local num_class = mw.ustring.lower(args.class)
		if num_class == 'cmath' then 
			if comp_number == nil then comp_number = require("Module:Complex Number") end
			math_lib = comp_number.cmath.init()
			tonumber_func = math_lib.toComplexNumber
		elseif num_class == 'qmath' then 
			if comp_number == nil then comp_number = require("Module:Complex Number") end
			math_lib = comp_number.qmath.init()
			tonumber_func = math_lib.toQuaternionNumber
		else
			local calc_checkor = require("Module:Complex Number/Calculate")
			local module_name, math_lib_name = calc_checkor.checkModuleClass(args.class)
			xpcall(function()
				local load_module = require("Module:"..module_name)
				if load_module ~= nil then
					local load_math_lib = load_module[math_lib_name]
					if load_module ~= nil then
						local func_type = type(function()end)
						local my_math_lib = (type(load_math_lib.init) == func_type) and load_math_lib.init() or load_math_lib
						if type(my_math_lib.constructor) == func_type then
							math_lib = my_math_lib
							tonumber_func = my_math_lib.constructor
						end
					end
				end
			end,function()end)
		end
	end
	local series = false
	local raw_val = false
    if args.series then
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
		series = yesno(args.series or 'no') 
    end
    if args.raw_value then
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
		raw_val = yesno(args.raw_value or 'no') 
	end
    if args.delnowiki then
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
		if yesno(args.delnowiki or 'no') then
			output_str = mw.text.unstripNoWiki( output_str )
		end
	end
	if args.delmsgnw then
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
    	if yesno(args.delmsgnw or 'no') then 
			output_str = mw.text.decode( output_str )
		end
	end
	local input_arg = {useOtherModule="yes"}
	for ikey, ivalue in pairs(args) do
		if mw.ustring.find(ikey,"last") then
			input_arg[ikey] = ivalue
		end
	end
	local num_arr=mw.text.split(require("Module:FunctionGraph")._functionGraph({expr},
		start_n,end_n,math.abs(start_n-end_n), nil, nil, input_arg,math_lib,tonumber_func).y1,',')
	local body=""
	if series==true then 
		for i=1,#num_arr do
			local last = num_arr[i-1]
			num_arr[i] = tonumber_func(num_arr[i]) + tonumber_func(last or 0)
		end
	end
	for i=1,#num_arr do
		body = body .. mw.ustring.gsub(output_str,"(%$[+-]?[%d]*)",function(str)
			local tail = ''
			if str=="$+" or str=="$-" then tail = mw.ustring.sub(str,-1) end
			local check, num = mw.ustring.find(str,"[+-]?[%d]+")
			if check then 
				num = tonumber(mw.ustring.sub(str, check, num) or '') or 1
			else
				num = 1
			end
			local idx = num+i-1
			if num < 0 then idx = num+i end
			if num == 0 then return tostring(i+start_n-1) .. tail end
			local get_val
			if raw_val then 
				if num < 0 and idx<1 then 
					get_val = tostring(input_arg['last'..math.abs(num)])
				else get_val = tostring(num_arr[idx]) end
			else
				if num < 0 and idx<1 then 
					get_val = tonumber_func(input_arg['last'..math.abs(num)])
				else get_val = tonumber_func(num_arr[idx]) end
			end
			
			if mw.text.trim(tostring(get_val or '')) ~= '' then return tostring(get_val) .. tail end
			return str
		end)
	end
    if args.preprocess then
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
		if yesno(args.preprocess or 'no') then
			return working_frame:preprocess( body )
		end
	end
	return body
end

function p.templateSequence(frame)
	if lib_var._arg_process == nil then lib_var = require('Module:Var') end
	local args, working_frame = lib_var._arg_process(frame)
	local output_str=args[1] or args['1'] or '$1,'
	local start_n = tonumber(args[2] or args['2'] or args.min or '1')or 1
	local end_n = tonumber(args[3] or args['3'] or args.max or '10')or 10
	local expr = mw.ustring.format(" %s ", args[4] or args['4'] or '$')
	
	if type(lib_tempPar._get_escape) ~= type(function()end) then lib_tempPar = require('Module:TemplateParameters') end
	
	output_str = mw.text.unstripNoWiki( output_str )
	expr = mw.text.unstripNoWiki(expr)
	if args.delmsgnw then
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
    	if yesno(args.delmsgnw or 'no') then 
			output_str = mw.text.decode( output_str )
			expr = mw.text.decode( expr )
		end
	end
	
	output_str = lib_tempPar._get_escape(output_str)
	expr = lib_tempPar._get_escape(expr)
	expr = mw.ustring.gsub(expr, "([^%$])%$([^%$])", function(prefix, suffix)
			return prefix.."\127MONEY\127"..suffix
		end)
	expr = mw.ustring.gsub(expr, "%$", "$$")
	expr = mw.ustring.gsub(expr, "\127MONEY\127", "$")

	local body = ''
	local num_arr = {}
	for i=start_n, end_n do
		local result = expr
		result = mw.ustring.gsub(result, "([^%$])%$([^%$])", function(prefix, suffix)
			return prefix..i..suffix
		end)
		result = mw.ustring.gsub(result, "%$%$", "$")
		result = mw.ustring.sub(result, 2, -2)
		num_arr[#num_arr + 1] = result
	end
	for i=1,#num_arr do
		body = body .. mw.ustring.gsub(output_str,"(%$[+-]?[%d]*)",function(str)
			local tail = ''
			if str=="$+" or str=="$-" then tail = mw.ustring.sub(str,-1) end
			local check, num = mw.ustring.find(str,"[+-]?[%d]+")
			if check then 
				num = tonumber(mw.ustring.sub(str, check, num) or '') or 1
			else
				num = 1
			end
			local idx = num+i-1
			if num < 0 then idx = num+i end
			if num == 0 then return tostring(i+start_n-1) .. tail end
			local get_val
			if num < 0 and idx<1 then 
				get_val = tostring(input_arg['last'..math.abs(num)])
			else get_val = tostring(num_arr[idx]) end
			
			if mw.text.trim(tostring(get_val or '')) ~= '' then return tostring(get_val) .. tail end
			return str
		end)
	end
	return working_frame:preprocess( body )
end

function p.exp10link(frame)
	if lib_var._arg_process == nil then lib_var = require('Module:Var') end
	local args, working_frame = lib_var._arg_process(frame)
    local input_number_str = args[1] or args['1'] or ''
    local digits = tonumber(input_number_str)
    if digits then
    	local test_num = '1'
    	if digits > 0 then
    		for i=1,digits do test_num = test_num .. '0' end
    	end
    	if working_frame:preprocess( "{{PAGENAME}}" ) == test_num then
    		return "'''10<sup>" .. input_number_str .. "</sup>'''"
    	end
    end
    return '[[1 E' .. input_number_str .. '|10<sup>' .. input_number_str .. '</sup>]]'
end
function p.MinusSignReplace(str)
	local input_str = str
	if type(str) == type({"table"}) then
		input_str = (str.args or {})[1] or str[1] or ''
	elseif type(str) ~= type("string") then
		input_str = tostring(str)
	end
	local body = mw.ustring.gsub(input_str,'%-','−')
	return body
end

function p.fractionalGaps(str, _width, _suffix)
	local input_str = str
	local width = tonumber(_width) or 4
	local suffix = _suffix or ''
	if type(str) == type({"table"}) then
		input_str = (str.args or {})[1] or str[1] or ''
		width = tonumber((str.args or {})[2] or str[2] or '') or 4
		suffix = (str.args or {})[3] or str[3] or ''
	elseif type(str) ~= type("string") then
		input_str = tostring(str)
	end
	input_str = input_str .. '.'
	local point_pos = mw.ustring.find(input_str, "%.")
	local int_str, fractional_str = mw.ustring.sub(input_str, 1, point_pos-1), mw.ustring.sub(input_str, point_pos+1, -1)
	fractional_str = mw.ustring.gsub(fractional_str, "[^%d%a]", '')
	local fractional_length = mw.ustring.len(fractional_str)
	local body = int_str .. '.'
	local i = 1
	while i <= fractional_length do
		local gap_part = mw.ustring.sub(fractional_str, i, i + width - 1)
		if gap_part == '' then break end
		if i <= 1 then body = body .. gap_part
		else
			body = body .. '<span style="margin-left: 0.25em">' .. gap_part ..'</span>'
		end
		i = i + width
	end
	return body .. (suffix ~= '' and ('<span style="margin-left: 0.25em">' .. suffix ..'</span>') or '')
end

function p.numberListTemplate(frame)
	if lib_var._arg_process == nil then lib_var = require('Module:Var') end
	local args, working_frame = lib_var._arg_process(frame)
    local input_number_str = args[1] or args['1'] or ''
    local failed = args.failed or ''
    local orginal_input_number_str = mw.text.trim(input_number_str)
	input_number_str = mw.ustring.gsub(input_number_str,'[Ii][Nn][Ff]','inf')
					:gsub('∞','inf')
					:gsub('[Nn][Aa][Nn]','nan')
	if mw.ustring.find(input_number_str,'[无無][穷窮限]') then input_number_str = 'inf' end
	local function out_text(text) return mw.text.tag( "div", {style="text-align: center;"}, mw.text.tag( "small", {}, text)) end
	if mw.ustring.find(input_number_str,'除') then return out_text("[[除以零]] 除以一 [[除以二]] [[除以三]] [[除法|>>]]") end
	if mw.ustring.find(input_number_str,'1/0') then return out_text("[[除以零]] 除以一 [[除以二]] [[除以三]] [[除法|>>]]") end
    input_number_str = mw.text.trim(input_number_str)
    local input_number = tonumber(input_number_str)
    if input_number then
		local inf_msg = out_text("[[擴展實數線|<<]] [[无穷|-∞]] .... [[-0]] [[0]] .... [[无穷|∞]] [[大数_(数学)|>>]]")
    	if not not tostring(input_number):lower():find('inf') then return inf_msg end
    	if not not tostring(input_number):lower():find('%-0') then return inf_msg end
		if not not tostring(input_number):lower():find('nan') then return out_text("[[NaN]] (參見:[[浮點數]]、[[算術溢出]])") end
    	
    	local digits_log = math.floor(math.log10(math.abs(input_number)))+1
    	local is_zero = false
    	if math.abs(input_number)<1e-8 then 
    		digits_log = 4 
    		is_zero = true
    	end
    	local sign = ((input_number>0)and 1 or((input_number==0 or input_number==-0)and 0 or-1))
    	local int, frac = math.modf(math.abs(input_number))
    	local int10, frac10 = math.modf(math.abs(input_number) * 10)
		local invocation = require('Module:Template invocation')
		local body = ''
    	if frac > 1e-8 then --小數模式
    		local get_frac = mw.ustring.gsub(input_number_str,'[%+%-]','')
    		local _,frac_start = get_frac:find('%.')
    		if frac_start then get_frac = get_frac:sub(frac_start+1,-1) 
    		else get_frac = tostring(frac):sub(3,-1) end
    		local get_frac10 = '0' .. get_frac:sub(2,-1)
    		local get_frac100 = '00' .. get_frac:sub(3,-1)
    		if frac10 > 1e-8 then
				body = body .. invocation.invocation("Numbers digits", {
					orginal_input_number_str,
					digit = '0.01',
					tail = ( sign < 0 and '-' or '' ) .. '0.'..get_frac100
				})
    		end
			body = body .. invocation.invocation("Numbers digits", { orginal_input_number_str, digit = '0.1'})
		end
		for digits=1,digits_log do
			local current_unit = tonumber('1e'..(digits-1))
			local current_mod = int % current_unit
			if current_mod == 0 then
				body = body .. invocation.invocation("Numbers digits", { orginal_input_number_str, digit = current_unit})
			end
		end
		if is_zero then body = body .. inf_msg end
		return body
    else return failed end
end
function p.combineNumber(frame)
	local args, working_frame
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        if lib_arg.getArgs == nil then lib_arg = require('Module:Arguments') end
        args = lib_arg.getArgs(frame, {
        	parentFirst=true,
        	trim = false,
			removeBlanks = false
        })
        working_frame = frame
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
        working_frame = mw.getCurrentFrame()
        if type(args) ~= type({}) then args = {frame} end
    end
    local input_article = args[1] or args['1'] or ''
    local spliter = {}
    input_spliter = mw.ustring.gsub(input_article, '(%d)', '%1%1%1')
    mw.ustring.gsub(input_spliter,'[%d%.]([^%d%.]+)[%d%.]',function(str)
    	spliter[str] =(spliter[str] or 0)+1
    	return str 
    end)
    local max_count = 0
    local spliter_str = args[2] or args['2'] or ','
    for value,v_count in pairs(spliter) do
    	if v_count > max_count then
    		max_count = v_count
    		spliter_str = value
    	end
    end
    if (args[2] or args['2']) ~= nil and (args[2] or args['2']) ~= '' then spliter_str = args[2] or args['2'] end
    if mw.text.trim(spliter_str or '') =='' then spliter_str = ' ' end
    local counting_sort = {}
     mw.ustring.gsub(input_article,'[%d%.]+',function(str)
     	local n_first, n_last = mw.ustring.find(str,'%d+')
     	if n_first then
     		local num = tonumber(mw.ustring.sub(str, n_first, n_last))
     		if num then counting_sort[num] = counting_sort[num] or str end
     	end
    	return str 
    end)
    local quick_sort = {}
    for value,v_count in pairs(counting_sort) do
    	quick_sort[#quick_sort + 1] = {value,v_count}
    end
    table.sort( quick_sort, function(left,fight) return left[1] < fight[1] end )

    local write_number = ''
    local output_arr = {}
    local trmp_str = ''
    for i=1,#quick_sort do
    	if type(write_number) ~= type(0) then 
    		write_number = quick_sort[i][1] 
    		trmp_str = '' .. quick_sort[i][2]
    	end
    	if quick_sort[i][1] + 1 ~= (quick_sort[i+1]or{quick_sort[i][1]-1})[1] then
    		if write_number ~= quick_sort[i][1] then
    			trmp_str = trmp_str .. "-"..quick_sort[i][2]
    		end
    		output_arr[#output_arr + 1] = trmp_str
    		write_number = ''
    	end
    end
	return table.concat( output_arr, spliter_str )
end 
return p