Module:TextPredicate
简介
TextPredicate用于解析一个text文本构成的布尔表达式。能够解析一段满足格式要求的文本作为表达式。可以进行与或非操作,可以进行判断。供其他模块调用。如textPredicate=require("Moudle:TextPredicate")
。
属性
符号
为避免与维基文本使用的特殊字符重复,允许符号重定义。
symbolOr
:表示“或”的符号。默认为|
。symbolAnd
:表示“与”的符号。默认为&
。symbolNot
:表示“非”的符号。默认为-
。symbolBrackets
:表示“括号”的两个符号。默认为()
。
一般而言匹配文本时需要更改symbolOr
符号,避免冲突。
值
_true
:绝对为真的表达式。_false
:绝对为假的表达式。
函数
生成
textPredicate.createExpress(text)
识别文本并生成表达式。规则与通常的布尔表达式相同,除规定符号外文本皆视为变量。
在不改变符号的情况下,表达式可以表示如:a&-b|(a&c)
。也可以表示如变量1|这个&(那个|-变量b)
。
判断
textPredicate:__call(names)
即textPredicate(names)
对一组变量表进行判断,判别表达式下是否成立。该表内应为变量名
或symbolNot变量名
,表示真或假。
textPredicate:__eq(other)
即textPredicate==other
,判断表达式内容实质是否相同。
textPredicate:__le(other)
即textPredicate<=other
,判断表达式内容实质是否被后者包含。即该表达式成立时后者必然成立。
textPredicate:isReal(bool)
判断表达式是否恒为真/假。与textPredicate==textPredicate._true
textPredicate==textPredicate._false
等效。
留空则判断表达式是否为真值。
计算
由于元方法支持有限,符号比较错乱。 自身运算表示并不返回值,而是将值赋值到第一个参数中。
textPredicate:__concat(other)
即textPredicate..other
,计算表达式的“与”。
自身运算为textPredicate:concat(other)
。
textPredicate:__add(other)
即textPredicate+other
,计算表达式的“或”。
自身运算为textPredicate:add(other)
。
textPredicate:__unm()
即-textPredicate
,计算表达式的“非”。
自身运算为textPredicate:unm(other)
。
textPredicate:__sub(other)
即textPredicate-other
,计算表达式的“差”。但如果调用方法则会同时返回表达式的“与”,
自身运算为textPredicate:sub(other)
。返回表达式的“与”。
textPredicate:changeListClone(list)
list
为一组变量文本。
计算表达式改变使用的变量组后的情况。默认不在list
中的变量值均为true
。
自身运算为textPredicate:changeList(other)
。
textPredicate:limitTo(list)
list
为一组变量文本。
限制表达式使用的变量组,默认不在list中的变量值均为false
。
迭代器
textPredicate:gAllowNames()
依次返回表达式允许情况的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