表单在form:功法查询页面创建

使用模板:功法查询传递参数

查询功能在模块:GongFa/query实现

特殊:执行查询/功法查询页面使用该功能


local p = {}

local SortedTable = require('Module:SortedTable')
local Name = mw.loadData("Module:Const/name")
local Attr
local Field = {}
local Link = require('Module:GongFaTable').link
function link(name, brief) return Link({name, brief = brief}) end

function lerr(...)
	error('\n'..mw.allToString(...))
end

local operator = {
	{function(t,args) return args[1](t)+args[2](t) end, level = 4, name = '+'},
	{function(t,args) return args[1](t)-args[2](t) end, level = 4, name = '-'},
	{function(t,args) return args[1](t)*args[2](t) end, level = 3, name = '*'},
	{function(t,args) return args[1](t)/args[2](t) end, level = 3, name = '/'},
	{function(t,args) return args[1](t)%args[2](t) end, level = 3, name = '%'},
	{function(t,args) return math.floor(args[1](t)%args[2](t)) end, level = 3, name = '\\'}, --5\2==2
	{function(t,args) return args[1](t) and args[2](t) end, level = 11, name = 'and'},
	{function(t,args) return args[1](t) or args[2](t) end, level = 12, name = 'or'},
}

for k,v in ipairs(operator) do
	setmetatable(v, { __tostring = function(this) return this.name end })
	v.isOp = true
end

function find(query)
	query = query or {}
	query['_id'] = { ["$regex"] = '^Data:GongFa\.tab' }
	query['id'] = {['$gte'] = 0}
	return mw.huiji.db.find(query)
end

function fit(arr,names,noError)
	if not arr then return nil end
	arr = mw.text.split(arr, '、', true)
	for i,pattern in ipairs(arr) do
		local flag
		for key,str in pairs(names) do
			if mw.ustring.find(str, pattern, 1, true) then
				arr[i] = key
				flag = true
				break
			end
		end
		if not flag and not noError then
			lerr(pattern,'不是有效的输入')
		end
	end
	return {['$in'] = arr}
end --标准化输入

function matchAll(str, arr)
	for k,v in ipairs(arr) do
		if not mw.ustring.find(str, v) then
			return false
		end
	end
	return true
end --字符串中同时包含多个匹配串

function p.e(frame) --p.e()
	local args = frame and frame:getParent().args or {['描述'] = '无色'}--['门派'] = '武当、少林',['描述'] = '刀法 无敌.天下' , ['品级'] = '123456789',  ['属性'] = '纯阳、混元',['描述'] = '(暂.说明',  ['排序'] = '{内力}/{占格}'
	local query = {}
	
	query.data0 = args['名称'] and {["$regex"] = args['名称'] }
	
	local showArgs = {}
	local des = args['描述']
	if des then
		local list = {}
		des = mw.text.split(des, ' ', true)
		for k,v in ipairs(des) do
			table.insert(list, {
				data99 = {["$regex"] = v}
			})
		end
		query["$and"] = list
		table.insert(showArgs,'描述')
	end
	
	if args['品级'] then
		local num = tonumber(args['品级'])
		if not num or num<=0 then lerr('[品级]应为一串0~9的数字') end
		local arr = {}
		while(num>0) do
			table.insert(arr, 10 - num%10)
			num = math.floor(num/10)
		end
		query.data2 = {['$in'] = arr}
	end
	
	query.data3 = fit(args['门派'], Name.gang)
	query.data4 = fit(args['属性'], Name.qi)
	
	local typ = args['类型']
	if typ then
		query["$or"] = {
			{data1 = fit(typ, Name.gongfa, true)},
			{data6 = fit(typ, Name['运功位'], true)},
		}
	end
	
	local result = find(query)
	
	if args['心法'] then
		local power = mw.loadData("Module:GongFa/power") 
		local arr = mw.text.split(args['心法'], ' ', true)
		local tmp = {}
		for k,v in ipairs(result) do
			local p0,p1 = power[v.data103],power[v.data104]
			if (p0 and matchAll(p0[1], arr)) or (p1 and matchAll(p1[1], arr)) then
				v['心法正练'] = p0[1]
				v['心法逆练'] = p1[1]
				table.insert(tmp,v)
			end
		end
		result = tmp
		table.insert(showArgs,'心法正练')
		table.insert(showArgs,'心法逆练')
	end
	local limit = tonumber(args['数量']) or 20
	local count = #result
	local sort = args['排序']
	if sort then
		Attr = mw.loadData("Module:Const/attr")
		local s = mw.ustring.gsub(sort, ' ', '')
		s = mw.ustring.gsub(s,'\n','')
		local func = makeTree(splitQuation(s))
		local change = require('Module:GongFa/value').change
		local st = SortedTable:new(limit)
		for i,item in ipairs(result) do
			item = change(item)
			local key = func(item)
			item[sort] = key
			st:insert(key, item)
		end
		result = st:out()
		table.insert(showArgs, sort)
		for k,v in pairs(Field) do
			table.insert(showArgs, k)
		end
		if #showArgs==2 and showArgs[1]==showArgs[2] then 
			showArgs[2]=nil 
		end
	else
		for i=limit+1,count do
			result[i] = nil
		end
	end
	if des then
		for k,v in ipairs(result) do
			v['描述'] = v.data99
		end
	end
	local str = '共查得'..count..'个符合条件的功法'
	if limit<count then 
		str = str..',显示其中的'..limit..'个'
	end
	str = str..':<br>\n'..wikitable(result, showArgs)
	return str
end

function out(tbl)
	local result = ""
	local first = true
	for k,v in pairs(tbl) do
		if not first then
			result = result..'\n'
		else
			first = false
		end
		result = result..link(v['名称'])
	end
	--mw.log(result)
	return result
end --格式化输出

function wikitable(tbl, args)
	local result = '<table class="wikitable">\n\n<tr>\n'
	result = result..'<th>'..'</th>\n'
	for k,v in pairs(args) do
		result = result..'<th>'..v..'</th>\n'
	end
	result = result..'</tr>\n\n'
	local brief = #tbl<=20
	for i,gf in ipairs(tbl) do
		result = result..'<tr>\n'
		result = result..'<td>'..link(gf['名称'], brief)..'</td>\n'
		for key,v in pairs(args) do
			local value = gf[v] or 0
			if value==nil then lerr(mw.dumpObject(gf), v) end
			result = result..'<td>'..value..'</td>\n'
		end
		result = result..'</tr>\n\n'
	end
	result = result..'</table>'
	mw.log(result)
	return result
end
	

function getKeyWord(s)
	local result = {}
	local flag = {} --忽略重复的字段
	for name in string.gmatch(s, 'data%d+') do
		if flag[name]==nil then
			table.insert(result, name)
			flag[name] = 1
		end
	end
	return result,s
end

local Chain = {print_depth=0, isChain=true}
Chain.__index = function(this, i) return Chain[i] end
function Chain:add(item)
	if not item then return end
	item = {item}
	if self.length==0 then
		self.head = item
	else
		item.left = self.tail
		self.tail.right = item
	end
	self.tail = item
	self.length = self.length + 1
	item.index = self.length
	self.list[self.length] = item
	return item
end
function Chain:combine(chain)
	if not chain then return self end --为空
	if type(chain)~='table' or not chain.isChain then 
		self:add(chain)
		return self
	end --不是链表
	if chain.length==0 then return self end --第二链表为空的链表
	if self.length==0 then return chain end --第一链表为空的链表
	--连接节点
	self.tail.right = chain.head
	chain.head.left = self.tail
	self.tail = chain.tail
	--更新链表长度与节点目录
	local len = self.length
	local len2 = chain.length
	for k=1,len2 do
		local node = chain.list[k]
		node.index = len+k
		self.list[len+k] = node
	end
	self.length = len + len2
	
	return self
end
function Chain:new(item)
  local result = {
  	length = 0,
  	list = {},
  	head = {},
  	tail = {}
  }
  setmetatable(result, self)
  if item then
  	result:add(item)
  end
  return result
end
function Chain:__tostring()
	local now = self.head
	local result = ''
	while now do
		local item = now[1]
		if type(item)=='table' then 
			if item.name then
				for i=1,Chain.print_depth do
					result = result..'....'
				end
				result = result..item.name..'\n'
			else
				Chain.print_depth = Chain.print_depth+1
				result = result..tostring(item)..'\n'
				Chain.print_depth = Chain.print_depth-1
			end
		else
			for i=1,Chain.print_depth do
				result = result..'....'
			end
			result = result..tostring(item)..'\n'
		end
		now=now.right
	end
	local len = #result
	if Chain.print_depth>0 then result = string.sub(result, 1, len-1) end
	return result
end

function toChain(s) --用运算符分割无括号的字符串,生成链表
	if not s or #s==0 then return Chain:new() end
	local len = mw.ustring.len(s)
	for k,v in ipairs(operator) do
		local from,to = mw.ustring.find(s,v.name,1,true)
		if from then
			local left = from>1 and mw.ustring.sub(s,1,from-1)
			local mid = v
			local right = to<len and mw.ustring.sub(s,to+1,len)
			left = toChain(left)
			right = toChain(right)
			return left:combine(mid):combine(right)
		end
	end
	--已分割至最小
	--mw.log(s)
	return Chain:new(s)
end

function splitQuation(s)  --解释括号
	if not s then return Chain:new() end
	local depth = 0
	local head = 0
	local tail = 0
	local len = mw.ustring.len(s) 
	for i=1,len do
		local char = mw.ustring.sub(s,i,i)
		if char=='(' or char=='('then
			if depth==0 then head=i end
			depth = depth + 1
		elseif char==')' or char==')'then
			depth = depth - 1
			if depth==0 then 
				tail=i 
				break
			end
		end
	end
	if head>0 then
		local left = head>1 and mw.ustring.sub(s,1,head-1)
		local mid = mw.ustring.sub(s,head+1,tail-1)
		local right = tail~=0 and tail~= len and mw.ustring.sub(s,tail+1,-1)
		left = toChain(left)
		mid = Chain:new(splitQuation(mid))
		right = splitQuation(right)
		--mw.log('left:\n'..tostring(left)..'\n'..'mid:\n'..tostring(mid)..'\n'..'right:\n'..tostring(right)..'\n\n')
		return left:combine(mid):combine(right)
	else
		return toChain(s)
	end
	--mw.logObject(chain)
end

function getDatum(node)
	if node==nil then return 0,true end --端点
	local item = node[1]
	if item==nil then lerr("'node' is not node :"..tostring(node)) end
	local typ = type(item)
	if typ=='table' then 
		if item.isChain then
			return makeTree(item),false
		end
		if item.isOp then
			return 0,true --两个运算符相邻
		end
		lerr(tostring(item))
	end
	return item,false
end

function makeTree(chain)
	local len = chain.length
	if len==1 then return arg2func(chain.head[1]) end
	local min = 2
	local max = 14
	local classified = {}
	for i=min,max do
		classified[i] = {}
	end
	local result
	for i=1,len do
		local node = chain.list[i]
		local item = node[1]
		local typ = type(item)
		if typ=='table' and item.isOp then
			local level = item.level
			table.insert(classified[level], node)
		end
	end
	for i=min,max do
		local list = classified[i]
		local size = #list
		for j=1,size do
			local item = list[j]
			local item_l,zero_l = getDatum(item.left)
			local item_r,zero_r = getDatum(item.right)
			local args = {
				[1] = item_l,
				[2] = item_r
			}
			local func = makeFunc(item[1][1], args)
			--lerr(item_l,zero_l,mw.dumpObject(item.left))
			local left = item.left
			if not zero_l then left = left.left end
			local right = item.right
			if not zero_r then right = right.right end
			if left==nil and right==nil then
				return func
			end
			func = {
				func,
				left = left,
				right = right,
				name = 'function'..j
			}
			result = func
			if left then left.right = func end
			if right then right.left = func end
		end
	end
	lerr(tostring(result.left)..'\n'..tostring(result)..'\n'..tostring(result.right))
end

function toboolean(s)
	if type(s)=='boolean' then return s end
	if s=='true' then return true end
	if s=='false' then return false end
end
function arg2func(v)
	local typ = type(v)
	if typ=='string' then
		local value = tonumber(v) or toboolean(v)
		if value==nil then --是字段名
			Field[v] = 1
			return function(t) return t[v] or 0 end
		else
			return function() return value end
		end
	elseif typ=='number' or typ=='boolean' then
		return function() return v end
	elseif typ=='table' then
		error('\n'..mw.dumpObject(v))
		--args[k] = makeFunc(v.func, v.args)
	end
	return v
end
function makeFunc(func, args)
	if func==nil then lerr('no func') end
	for k,v in ipairs(args) do
		args[k] = arg2func(v)
	end
	--mw.log(func)
	return (function(t) return func(t, args) end)
end
	

function p.t()
	local s = '品级+data2'--'50+6and1+(9*(2+3))+5'
	local chain = splitQuation(s)
	local func = makeTree(splitQuation(s))
	mw.log(func({data2=3}))
	--mw.logObject(Chain)
end

function p.s()
	mw.log(link('大拙手'))
end

return p
avatar