2023年政策修订增补工作正在进行中,欢迎参与!
  • Moegirl.ICU:萌娘百科流亡社群 581077156(QQ),欢迎对萌娘百科运营感到失望的编辑者加入
  • Moegirl.ICU:账号认领正在试运行,有意者请参照账号认领流程

Module:TextPredicate

萌娘百科,万物皆可萌的百科全书!转载请标注来源页面的网页链接,并声明引自萌娘百科。内容不可商用。
跳转到导航 跳转到搜索
Template-info.svg 模块文档  [查看] [编辑] [历史] [刷新]

简介

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._truetextPredicate==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