TextPredicate用于解析一个text文本构成的布尔表达式。能够解析一段满足格式要求的文本作为表达式。可以进行与或非操作,可以进行判断。供其他模块调用。如textPredicate=require("Moudle:TextPredicate")
。
为避免与维基文本使用的特殊字符重复,允许符号重定义。
symbolOr
:表示“或”的符号。默认为|
。symbolAnd
:表示“与”的符号。默认为&
。symbolNot
:表示“非”的符号。默认为-
。symbolBrackets
:表示“括号”的两个符号。默认为()
。一般而言匹配文本时需要更改symbolOr
符号,避免冲突。
_true
:绝对为真的表达式。_false
:绝对为假的表达式。识别文本并生成表达式。规则与通常的布尔表达式相同,除规定符号外文本皆视为变量。
在不改变符号的情况下,表达式可以表示如:a&-b|(a&c)
。也可以表示如变量1|这个&(那个|-变量b)
。
即textPredicate(names)
对一组变量表进行判断,判别表达式下是否成立。该表内应为变量名
或symbolNot变量名
,表示真或假。
即textPredicate==other
,判断表达式内容实质是否相同。
即textPredicate<=other
,判断表达式内容实质是否被后者包含。即该表达式成立时后者必然成立。
判断表达式是否恒为真/假。与textPredicate==textPredicate._true
textPredicate==textPredicate._false
等效。
留空则判断表达式是否为真值。
由于元方法支持有限,符号比较错乱。 自身运算表示并不返回值,而是将值赋值到第一个参数中。
即textPredicate..other
,计算表达式的“与”。
自身运算为textPredicate:concat(other)
。
即textPredicate+other
,计算表达式的“或”。
自身运算为textPredicate:add(other)
。
即-textPredicate
,计算表达式的“非”。
自身运算为textPredicate:unm(other)
。
即textPredicate-other
,计算表达式的“差”。但如果调用方法则会同时返回表达式的“与”,
自身运算为textPredicate:sub(other)
。返回表达式的“与”。
list
为一组变量文本。
计算表达式改变使用的变量组后的情况。默认不在list
中的变量值均为true
。
自身运算为textPredicate:changeList(other)
。
list
为一组变量文本。
限制表达式使用的变量组,默认不在list中的变量值均为false
。
依次返回表达式允许情况的bits值以及与之对应的一个变量文本的表。该表内容与#textPredicate:__call(names)一致。
local clone=function(self)--浅表克隆 local new=setmetatable({},getmetatable(self)) for k,v in pairs(self) do new[k]=v end return new end local indexOf=function(list,item)--获得序号 for i=1,#list do if list[i]==item then return i end end end local merge= function(...)--列表合并 查重 local arrays = { ... } local result = {} for _,array in ipairs(arrays) do for _, v in ipairs(array) do if not indexOf(result,v) then table.insert(result, v) end end end return result end local intersection=function(t1, t2) local result = {} for _,v in ipairs(t1) do if indexOf(t2,v) then table.insert(result, v) end end return result end local bit32 = require( 'bit32' ) function bit32.set(bits,index,bool)--获取index处的真值 return bit32.replace(bits,bool and 1 or 0,index-1) end function bit32.get(bits,index)--设置index处的真值 return bit32.extract(bits,index-1)==1 end function bit32.count(bits,bool) local count=0 local value=bool and 1 or 0 for i=0,31 do if bit32.extract(bits,i)==value then count=count+1 end end return count end --充当bool判断式的bits local bitsbool={ } function bitsbool.create(tagbits,valuebits)--依靠tag表示位需要判别,value表示位的值 return setmetatable({tag=tagbits or 0,value=valuebits and bit32.band(tagbits,valuebits) or 0},bitsbool) end bitsbool.__index = bitsbool function bitsbool:set(index,value)--设置位 local bits=bit32.lshift(1,index-1) self.tag=bit32.bor(self.tag,bits) if value then self.value=bit32.bor(self.value,bits) end end bitsbool._true=bitsbool.create(0,0)--全允许,即true function bitsbool:__call(valuebits)--判断允许 valuebits是指与bitsbool的value类变量 return bit32.band(valuebits,self.tag)==self.value end function bitsbool:__mul(bitsbool)--判断无冲突 local tag=bit32.band(bitsbool.tag,self.tag) return bit32.band(bitsbool.value,tag)==bit32.band(self.value,tag) end function bitsbool:__eq(bitsbool)--判断等同 return bitsbool.tag==self.tag and bitsbool.value==self.value end function bitsbool:__le(bitsbool)--判断被包含或等同 return bit32.bor(bitsbool.tag,self.tag)==self.tag and bitsbool.value==bit32.band(self.value,bitsbool.tag) end function bitsbool:__lt(bitsbool)--判断完全被包含 return self~=bitsbool and self<=bitsbool end function bitsbool:__unm()--取反 return bitsbool.create(self.tag,bit32.bnot(self.value)) end function bitsbool:_differ(other) if other.tag==self.tag then local v=bit32.bxor(other.value,self.value) if bit32.count(v,true)==1 then return bitsbool.create(self.tag-v,self.value) end end end function bitsbool:_and(other)--交集 即and运算 local tag=bit32.bor(other.tag,self.tag) local a=bit32.band(other.tag,self.tag) local error=bit32.bxor(bit32.band(a,other.value),bit32.band(a,self.value))--如果tag同开启位置有不同要求值,意味着不可能为true if error~=0 then return nil end return bitsbool.create(tag,bit32.bor(other.value,self.value)) end function bitsbool:trans(transer)--改变次序 local result= bitsbool.create(0,0) for index,newIndex in pairs(transer) do result.tag=bit32.set(result.tag,newIndex,bit32.get(self.tag,index)) result.value=bit32.set(result.value,newIndex,bit32.get(self.value,index)) end return result end function bitsbool:isTrue() return self.tag==0 end function bitsbool:getbits_step(index)--遍历判断元 local value repeat value=bit32.lshift(1,index) index=index+1 if bit32.band(self.tag,value)~=0 then return index,bit32.band(self.value,value)~=0 end until(value>self.tag) end function bitsbool:getbits()--遍历判断元 return bitsbool.getbits_step,self,0 end function bitsbool:__tostring() local t={} for index,value in self:getbits() do table.insert(t,value and index or -index) end return table.concat(t,"&") end --充当bool判断式的bits组 local bitsboolTable={ } function bitsboolTable.create(bitsbools) bitsbools=bitsbools or {} return setmetatable(bitsbools,bitsboolTable) end bitsboolTable.__index = bitsboolTable bitsboolTable._true=bitsboolTable.create({bitsbool._true}) bitsboolTable._false=bitsboolTable.create() function bitsboolTable:contains(bitsbool)--判断式存在 for _,value in ipairs(self) do if not bitsbool.value or not value.value then return false end if bitsbool<=value then return true end end return false end function bitsboolTable:__le(other)--判断被包含 for _,bitsbool in ipairs(self) do if not other:contains(bitsbool) then return false end end return true end function bitsboolTable:__eq(other)--判断全同 if #self~=#other then return false end return self:__le(other) end function bitsboolTable:insertbool(bitsbool)--添加判断式 if bitsbool==nil then return end if self:contains(bitsbool) then return end local index=#self while index>=1 do--移除包含项 if bitsbool>self[index] then table.remove(self,index) end local d=bitsbool:_differ(self[index]) if d then--合并项 table.remove(self,index) self:insertbool(d) return end index=index-1 end table.insert(self,bitsbool) end function bitsboolTable:__call(valuebits)--判断允许 valuebits是指与bitsbool的value类变量。即一种情况 for _,bitsbool in ipairs(self) do if bitsbool(valuebits) then return true end end return false end function bitsboolTable:isReal(bool)--是否为简单真值。 if bool or bool==nil then if #self==1 and self[1]==bitsbool._true then return true end end if not bool then if #self==0 then return true end end return false end bitsboolTable.orbool=bitsboolTable.insertbool--or判断式 function bitsboolTable:andbool(bitsbool)--and判断式 for index,value in ipairs(self) do self[index]=bitsbool+value end end function bitsboolTable:_or(other)--or操作 local result=clone(self) for _,bitsbool in ipairs(other) do result:orbool(bitsbool) end return result end function bitsboolTable:_and(other)--and操作 local result=bitsboolTable.create() for _,bitsbool1 in ipairs(self) do for _,bitsbool2 in ipairs(other) do result:orbool(bitsbool1:_and(bitsbool2)) end end return result end function bitsboolTable.notbool(bool)--not判断式 local result=bitsboolTable.create() for index,value in bool:getbits() do local newbitsbool=bitsbool.create() newbitsbool:set(index,not value) result:orbool(newbitsbool) end return result end function bitsboolTable:_not()--not操作 local result=bitsboolTable._true for _,bitsbool in ipairs(self) do result=result:_and(bitsboolTable.notbool(bitsbool)) end return result end function bitsboolTable:__unm()--取反 return self:_not() end function bitsboolTable:trans(transer)--转换参考 local result=bitsboolTable.create() for _,bitsbool in ipairs(self) do local bool=bitsbool:trans(transer) if bool:isTrue() then--目标的变量缺失导致为真 return bitsboolTable._true end result[#result+1]=bool end return result end function bitsboolTable:limit_trans(transer)--转换参考,凡是具有transer中未涵盖项的bitsbool都跳过, local tag=0 for index,_ in pairs(transer) do tag=bit32.set(tag,index,true) end local result=bitsboolTable.create() for _,bitsbool in ipairs(self) do local bool=bitsbool:trans(transer) if bit32.band(bitsbool.tag,tag)==bitsbool.tag then result[#result+1]=bool end end return result end function bitsboolTable:__tostring() local t={} for _,bitsbool in ipairs(self) do table.insert(t,tostring(bitsbool)) end if #t==0 then return "false" end return table.concat(t,"|") end --标记基础 local textPredicate={symbolOr="|",symbolAnd="&",symbolNot="-",symbolBrackets="()"} --构造 function textPredicate.base(tab) tab=tab or {} tab.list=tab.list or {} tab.bool=tab.bool or bitsboolTable.create() return setmetatable(tab,textPredicate) end textPredicate.__index = textPredicate function textPredicate.baseBool(bool,list) list=list or {} local boolTable=bool and bitsboolTable._true or bitsboolTable._false return textPredicate.base{list=list,bool=boolTable} end textPredicate._true=textPredicate.baseBool(true) textPredicate._false=textPredicate.baseBool(false) function textPredicate.createArgs(tabs)--需要是一组tab,每组tab作为and使用 local this=textPredicate.base() this:addTabs(tabs) return this end function textPredicate.createText(text)--需要是一个text。先计算与,后计算或。 local this=textPredicate.base() this:addText(text) return this end function textPredicate.createExpress(text)--需要是一个表达式。 local this=textPredicate.base() this:addExpress(text) return this end function textPredicate:_bitHuge()--使用的长度的bit的最大值 return bit32.lshift(1,#self.list)-1 end function textPredicate:_indexof(name)--标记对应序号 return indexOf(self.list,name) end function textPredicate:_addName(name)--添加标记并获得序号 local index=self:_indexof(name) if index then return index end table.insert(self.list,name) return #self.list end --构造-获取 function textPredicate:addTab(names)--一组&标记 local bitsbool=bitsbool.create(0,0) for _,name in ipairs(names) do if name:sub(1,#self.symbolNot)==self.symbolNot then name=name:sub(#self.symbolNot+1) value=false else value=true end local index=self:_addName(name) bitsbool:set(index,value) end if bitsbool.tag~=0 then self.bool:insertbool(bitsbool) end end function textPredicate:addTabs(args)--一组&标记 for _,tab in ipairs(args) do self:addTab(tab) end end function textPredicate:addText(text)--一组标记 for textAnd in mw.text.gsplit(text,self.symbolOr) do self:addTab(mw.text.split(text,self.symbolAnd)) end end --表达式识别 function textPredicate._matchName(text,indexIn)--名字 local index=indexIn while index<=#text do if text:sub(index,index+#textPredicate.symbolOr-1)==textPredicate.symbolOr or text:sub(index,index+#textPredicate.symbolAnd-1)==textPredicate.symbolAnd or text:sub(index,index+#textPredicate.symbolNot-1)==textPredicate.symbolNot then break end index=index+1 end return indexIn,index-1 end function textPredicate:_matchItemExpress(text,index)--块 --mw.log("item",text:sub(index)) local b,e=text:find("^%b"..self.symbolBrackets,index)--括号 if b then return self:_matchExpress(text:sub(b+1,e-1),1),e end if text:sub(index,index+#self.symbolNot-1)==self.symbolNot then--非 local bool,e=self:_matchItemExpress(text,index+#self.symbolNot,list) return bool:_not(),e end local b,e=textPredicate._matchName(text,index)--名字 if b then local index=self:_addName(text:sub(b,e)) local bitsbool=bitsbool.create(0,0) bitsbool:set(index,true) --mw.log("bitsboolTable",bitsboolTable.create{bitsbool}) return bitsboolTable.create{bitsbool},e end error("错误的表达式") end function textPredicate:_matchExpress(text,index,bool) if not bool then bool,index=self:_matchItemExpress(text,index) index=index+1 end local other if text:sub(index,index+#textPredicate.symbolOr-1)==self.symbolOr then--或 index=index+#textPredicate.symbolOr other,index=self:_matchItemExpress(text,index) bool=bool:_or(other) elseif text:sub(index,index+#textPredicate.symbolAnd-1)==textPredicate.symbolAnd then--与 index=index+#textPredicate.symbolAnd other,index=self:_matchItemExpress(text,index) bool=bool:_and(other) end if index>=#text then return bool end return self:_matchExpress(text,index+1,bool) end function textPredicate:addExpress(text)--追加一个表达式 if not text then return end local bool=self:_matchExpress(text,1) if self.bool:isReal(false) then self.bool=bool else self.bool=self.bool:_or(bool) end end --计算 function textPredicate._transer(list,newlist) local transer={} for index,name in ipairs(list) do local newIndex=indexOf(newlist,name) transer[index]=newIndex end return transer end function textPredicate:changeListClone(list)--获得改变list的副本 local new=textPredicate.base{list=list} local transer=textPredicate._transer(self.list,list) new.bool=self.bool:trans(transer) return new end function textPredicate:changeList(list)--改变list local transer=textPredicate._transer(self.list,list) self.list=new.list self.bool=self.bool:trans(transer) end function textPredicate:limitTo(list)--限制list,默认不在list中的值为false,即跳过项 list=intersection(list,self.list) local new=textPredicate.base{list=list} local transer=textPredicate._transer(self.list,list) new.bool=self.bool:limit_trans(transer) return new end function textPredicate:_sameList(other)--返回两名字组一致的textPredicate,以便对比 local t=merge(self.list,other.list) return self:changeListClone(t),other:changeListClone(t) end function textPredicate:unm()--计算自身取反 self.bool=self.bool:_not() end function textPredicate:__unm()--计算取反 result.bool=result.bool:_not() return result end function textPredicate:sub(other)--计算自身减法 local t=merge(self.list,other.list) self:changeList(t) other=other:changeListClone(t) local bool=self.bool:_and(other.bool:_not()) local cuted=self.bool:_and(other.bool) local first,second if bool then self.bool=bool end if cuted then other.bool=cuted end return other end function textPredicate:__sub(other)--计算减法 self,other=self:_sameList(other) local bool=self.bool:_and(other.bool:_not()) local cuted=self.bool:_and(other.bool) local first,second if bool then first=self first.bool=bool end if cuted then second=other second.bool=cuted end --mw.log("新",first,second) return first,second end function textPredicate:add(other)--计算自身or local t=merge(self.list,other.list) self:changeList(t) other=other:changeListClone(t) self.bool=self.bool:_or(other.bool) end function textPredicate:__add(other)--计算or local result,other=self:_sameList(other) result.bool=result.bool:_or(other.bool) return result end function textPredicate:concat(other)--计算自身and local t=merge(self.list,other.list) --mw.log("原",self,other) self:changeList(t) other=other:changeListClone(t) self.bool=self.bool:_and(other.bool) end function textPredicate:__concat(other)--计算and local result,other=self:_sameList(other) result.bool=result.bool:_and(other.bool) return result end textPredicate._or=textPredicate.__add textPredicate._and=textPredicate.__concat textPredicate._sub=textPredicate.__sub textPredicate._unm=textPredicate.__unm --功能-判断 function textPredicate:isReal(bool)--是否为简单真值。 return self.bool:isReal(bool) end function textPredicate:notReal(bool)--是否非简单真值。 return not self.bool:isReal(bool) end function textPredicate:__le(other)--判断属于 self,other=self:_sameList(other) return self.bool<=other.bool end function textPredicate:__eq(other)--判断等同 self,other=self:_sameList(other) return self.bool==other.bool end textPredicate._le=textPredicate.__le function textPredicate:_namesToBitsBool(names)--一组&标记 local bitsbool=bitsbool.create(0,0) for _,name in ipairs(names) do if name:sub(1,#self.symbolNot)==self.symbolNot then name=name:sub(#self.symbolNot+1) value=false else value=true end local index=self:_indexof(name) if index then bitsbool:set(index,value) end end return bitsbool end function textPredicate:__call(names)--对case判断从属。判断对象应当是table return self.bool:contains(self:_namesToBitsBool(names)) end --遍历与名字 function textPredicate._getAllowValues_step(self,valuebits) while valuebits<=self:_bitHuge() do valuebits=valuebits+1 if self.bool(valuebits) then return valuebits end end end function textPredicate:gAllowValues()--迭代器--返回所有允许的case,bits值 return textPredicate._getAllowValues_step,self,0 end function textPredicate:getNames(bitbool)--获得每位对应名字 local names={} for index=1,#self.list do if bit32.get(bitbool.tag,index)then local name=self.list[index] if not bit32.get(bitbool.value,index)then name="-"..name end table.insert(names,name) end end return names end function textPredicate:getCaseNames(valuebits)--获得每位对应名字 local names={} for index=1,#self.list do local name=self.list[index] assert(name,#self.list) if not bit32.get(valuebits,index)then name="-"..name end table.insert(names,name) end return names end function textPredicate._getAllowNames_step(self,valuebits) while valuebits<=self:_bitHuge() do valuebits=valuebits+1 if self.bool(valuebits) then return valuebits,self:getCaseNames(valuebits) end end end function textPredicate:gAllowNames()--迭代器--返回所有允许的case,bits值以及对应的names return textPredicate._getAllowNames_step,self,0 end function bit32.set(bits,index,bool)--获取index处的真值 return bit32.replace(bits,bool and 1 or 0,index-1) end textPredicate.getBitsBool=bit32.get function textPredicate:valueText()--以符号为间隔转换为文本 local t={} for _,bitbool in ipairs(self.bool) do local b=self:getNames(bitbool) table.insert(t,table.concat(b,self.symbolAnd)) end return table.concat(t,self.symbolOr) end function textPredicate:__tostring() local text=self:valueText() if #text==0 then text=(#self.bool==0) and "false" or "true" end return text end return textPredicate