模块:时间线

来自有兽档案馆
文档图示 模块文档[创建] [跳转到代码]

本模块还没有文档页面。

您可以创建文档以让编者更好地理解本模块的用途。
编者可以在本模块的沙盒创建 | 镜像和测试样例创建页面进行实验。
请将模块自身所属的分类添加在文档中。本模块的子页面
local module = {}
 
local getArgs = require('Module:Arguments').getArgs

--定义每次开头都是时间段而不是时间点
--辅助处理trim
function module.trim_step(text,patterns)
	for	_,pattern in ipairs(patterns) do
		local b,e=text:find(pattern)
		if b then
			return true,string.sub(text,e+1)
		end
	end
	return false,text
end
function module.trim(text,patterns)
	local bool=true
	while bool do
		bool,text=module.trim_step(text,patterns)
	end
	return text
end
function module.trimCount(text,patterns)
	local bool=true
	local count=-1
	while bool do
		bool,text=module.trim_step(text,patterns)
		count=count+1
	end
	return text,count
end

--时间线/事件元表
local timeLine={format={},analysis={}}

function timeLine:timeSupply()--补足省略前缀时间
	if self.time~=nil then
		if timeLine.lastLine~=nil then
			--mw.log("time",self.time,self.time:getNumber())
			--mw.log("timeUse",timeLine.lastLine.time,timeLine.lastLine.time:getNumber())
			self.time:supply(timeLine.lastLine.time,true,false)
			--mw.log("totime",self.time,self.time:getNumber())
			--mw.log(self.time,self.time:compare(timeLine.lastLine.time),timeLine.lastLine.time)
		end
	elseif timeLine.lastLine then
		self.time=mw.clone(timeLine.lastLine.time)
		--mw.log(tostring(defaultTime).."--same--"..tostring(this))
	end
end
function timeLine.appendText(text)--为最后创建的timeLine追加文本
	if timeLine.lastLine then
		if timeLine.lastLine.text then
			timeLine.lastLine.text=timeLine.lastLine.text..timeLine.format.split..text
		else
			timeLine.lastLine.text=text
		end
	end
	return timeLine.lastLine
end
function timeLine.base(args)
	return setmetatable(args or {},timeLine)
end
timeLine.__index = timeLine
function timeLine.title(titleLevel)
	assert(titleLevel,"标题层级不能为nil")
	return timeLine.base{titleLevel=titleLevel}
end
function timeLine.root()
	return timeLine.title(0)
end
function timeLine.create(withTimeText,parent)--带时间文本时间数字化·文本化函数
	assert(withTimeText~=nil and withTimeText~="","被分析文本不能为空")
	local titleLevel
	withTimeText,titleLevel=module.trimCount(withTimeText,timeLine.analysis.title)
	withTimeText=module.trim(withTimeText,timeLine.analysis.trim)
	withTimeText=module.trim(withTimeText,timeLine.analysis.sameTimeTable)
	local time,index=timeLine.getTime(withTimeText)
	if index==1 then
		time=nil
	end
	local text=module.trim(withTimeText:sub(index),timeLine.analysis.timeTextSplit)
	if #text+titleLevel==#withTimeText then--这是一行不具有时间效用的文本,实质为上一行文本的扩展部分。
		return timeLine.appendText(text)
	end
	local line=timeLine.base{time=time,text=text,titleLevel=titleLevel>0 and titleLevel}
	line:timeSupply()
	if parent then
		parent:insert(line)
	end
	timeLine.lastLine=line
	return line
end

function timeLine.titleMake(fulltime,level)--制作标题
	time=mw.clone(fulltime)
	--mw.log("->",timeLine.format.titleUnitList[level+timeLine.format.titleUnit-1],time)
	time:coverUnit(timeLine.format.titleUnitList[level+timeLine.format.titleUnit-1],true)
	if time:isEmpty() or time==fulltime then--没有可拆分信息
		return nil
	end
	local tag,range=time.accuracy:getMin()
	--mw.log(tag,range)
	local line=timeLine.title(timeLine.format.titleTopLevel+level-1)
	line.time=time
	return line
end
function timeLine:_insertTitile(newLine,index)--实际插入函数
	--mw.log("insert",self:currentlevel(),timeLine.format.titleLevel,self.titleLevel)
	if self.titleLevel and self:currentlevel()<timeLine.format.titleLevel then
		--mw.log("make",self:currentlevel()+1)
		local tl=timeLine.titleMake(newLine.time,self:currentlevel()+1)
		if not tl then--变成标题
			newLine.titleLevel=timeLine.format.titleTopLevel+self:currentlevel()
			newLine.parent=self
			table.insert(self,index,newLine)
		else
			tl.parent=self
			table.insert(self,index,tl)
			tl:_insertTitile(newLine,1)
		end
	else
		newLine.parent=self
		table.insert(self,index,newLine)
	end
end
function timeLine:move(otherLine,b,e)--辅助函数,转移数据
	--mw.log(tostring(self.time).."转移数据删除",b,e)
	e=e or b
	for i=b,e do--转移数据添加
		--mw.log("转移数据添加",i,self[i].time)
		otherLine:insert(self[i])
	end
	while e>=b do--转移数据删除
		--mw.log(self.time,"转移数据删除",e,self[e].time)
		table.remove(self,e)
		e=e-1
	end
end
function timeLine:_insert(newLine,index)--实际插入函数
	newLine.parent=self--记录父时间线
	table.insert(self,index,newLine)
end
function timeLine:insert(newLine)--插入时间函数
	local i=#self
	while i>=1 and newLine do
		local compareResult=newLine:compareTime(self[i])
		--mw.log(tostring(self[i].time).."-"..compareResult.."-"..tostring(newLine.time))
		if compareResult==timeLine.compareTime.inside then--包含,置入其内部
			--mw.log(tostring(self.time).."置入"..tostring(self[i].time).."数据"..tostring(newLine.time))
			newLine= self[i]:insert(newLine)
		elseif compareResult==timeLine.compareTime.equal then--相同。直接插入,这之后再处理
			break
			--if self:compare(newLine)~=timeLine.compare.equal then
				--newLine= self[i]:insert(newLine)--置入
			--else
				--break
			--end
		elseif compareResult==timeLine.compareTime.include then--需要转移数据
			local index=i-1
			while index>=1 and self[index]:compareTime(newLine)==timeLine.compareTime.inside do
				index=index-1
			end
			self:move(newLine,index+1,i)--转移数据的末端
			i=index
			break
		elseif compareResult~=timeLine.compareTime.before then--=timeCompare.before or compareResult==timeCompare.conflict  then--越界或不正确(?),插入
			break
		end
		i=i-1
		--compareResult==timeCompare.after 继续
	end
	if not newLine then return end
	--mw.log(self.time,i+1,"追加数据",newLine.time)
	self:_insert(newLine,i+1)
end
function timeLine:currentlevel()--实际层数
	if self.parent then
		return self.parent:currentlevel()+1
	end
	return 0
end
function timeLine:level()--缩进层数
	if self.titleLevel then
		return 0
	end
	return self.parent:level()+1
end
timeLine.format.timeToText=function(self,time,parentTime)
	local tag=time:getMin()
	if parentTime and self.cut then
		time:coverRange(parentTime)
	end
	local timeText=time:format(self.pattern,self.ignore)
	if #timeText==0 then
		timeText=self.sameTimeTable[tag] or self.sameTimeTable[0]
	end
	return timeText
end
timeLine.format=setmetatable(timeLine.format,{--格式化输出文本
	__call=function(self,timeLine)
		local time=timeLine.time
		if not time then return nil end
		local timeText=self:timeToText(time,timeLine.parent and timeLine.parent.time)
		--mw.log(timeLine.time.from)
		
		if timeLine.titleLevel then
			local builder={string.rep(self.title,timeLine.titleLevel),timeText,string.rep(self.title,timeLine.titleLevel)}
			if timeLine.text and #timeLine.text>0 then
				table.insert(builder,timeLine.text)
			end
			return table.concat(builder)
		end
		local builder={self.preTime,timeText,self.afterTime}
		
		if self.alignLength>string.len(timeText) then
			local m,r=math.modf(self.alignLength/2-((#timeText+mw.ustring.len(timeText))/4))
			if m>=1 and r>0 then
				table.insert(builder,"   ")
				table.insert(builder,string.rep(" ",m-1))
			else
				table.insert(builder,string.rep(" ",m))
			end
		elseif self.alignLength>0 then
			table.insert(builder," ")
		end
		local level=timeLine:level()--
		table.insert(builder,1,string.rep(self.preRange,level))
		table.insert(builder,1,self.pre)
		table.insert(builder,timeLine.text)
		table.insert(builder,self.after)
		table.insert(builder,string.rep(self.afterRange,level))
		return table.concat(builder)
	end
})

function timeLine:insertText(withTimeText)--插入文本 解析为timeLine
	if withTimeText==nil or withTimeText=="" then return end
	return timeLine.create(withTimeText,self)
end
function timeLine:_sort()--整理
	local sameCount=0
	local index=#self
	while index>1 do
		if self[index].time==self[index-1].time then
			sameCount=sameCount+1
		else
			if sameCount>0 and self[index].time~=self.time then
				self:move(self[index],index+1,index+sameCount)
			end
			sameCount=0
		end
		index=index-1
	end
	if sameCount>0 and self[index].time~=self.time then
		self:move(self[index],index+1,index+sameCount)
	end
	for _,child in ipairs(self) do
		child:_sort()
	end
end
function timeLine:sort()--整理 同期排列
	if self.format.indentSameTime then
		self:_sort()
	end
	return self
end
function timeLine:toArgs(args)
	args=args or {}
	local text=self:format()
	
	args[#args+1]=text
	for _,child in ipairs(self) do
		child:toArgs(args)
	end
	return args
end
function timeLine:__tostring()
	return table.concat(self:toArgs(),timeLine.format.split)
end
module.timeLine=timeLine--供继承

--参数预处理
function module.preArgs_step(tab,state)
	while true do
		if state.gsplit[1] then
			local _f=state.gsplit[1]
			local value
			state.gsplit[3]=_f(state.gsplit[2],state.gsplit[3])
		
			if state.gsplit[3] then
				return state,state.gsplit[3]
			end
		end
		--下一个arg
		local arg=tab.args[state.index]
		if not arg then return nil end--结束遍历
		state.index=state.index+1
		state.gsplit={mw.text.gsplit(arg, tab.sentenceSplit)}
	end
end
function module.preArgs(args)--迭代器
	local tab={
		args=args,
		sentenceSplit=args.sentencesplit or args.ss or args["句段分割符"] or "\n",--识别用
	}
	local state={
		index=1,
		gsplit={},
	}
	return module.preArgs_step,tab,state
end
--主函数
function module.timeModule(args)
	local from=args.from or args["原语言"]
	local to=args.to or args["目标语言"]
	local o_timezone=args.o_timezone or args.o_tz or args["原时区"]
	local c_timezone=args.c_timezone or args.c_tz or args["现时区"]
	local connect=args.timeformatrangesplit or args.tfrs or args["时间格式-时段连接符"] or "到"
	local timeModule=require("Module:模糊时间")
	timeModule.initialize(from,to,connect)
	return timeModule
end
function module.argsSet(args)--时间线参数设置
	--识别用
	timeLine.analysis.timeTextSplit={ "^%s", "^% ", }
	local filterAdd=function(tab,text)
		if text and text~="\t" and text~="\n" and text~="\r" and text~="\0" and text~="" then
			table.insert(tab,"^"..text)
		end
	end
	local timeTextSplit=args["time-textsplit"] or args.tts or args["时间-文本分割符"] or ","
	filterAdd(timeLine.analysis.timeTextSplit,timeTextSplit)
	timeLine.analysis.trim={ "^%s", "^% " }
	local bullet=args.bullet or args.b or args["项目符号"] or "\*"
	filterAdd(timeLine.analysis.trim,bullet)
	timeLine.analysis.title={}
	local timeTitle=args.timetitle or args.tt or args["时间标题符"] or "="
	filterAdd(timeLine.analysis.title,timeTitle)
	filterAdd(timeLine.analysis.timeTextSplit,timeTitle)
	timeLine.analysis.sameTimeTable={"^同期","^同年","^同月","^同日","^同时"}
	--格式化用
	timeLine.format.alignLength=tonumber(args.alignlength or args.al or args["对齐长度"]) or 0--18
	timeLine.format.pre=args.presentence or args.ps or args["文本前符"] or ""
	timeLine.format.after=args.aftersentence or args.as or args["文本后符"] or ""
	timeLine.format.preRange=args.prerange or args.pr or args["时段前符"] or bullet
	timeLine.format.afterRange=args.afterrange or args.ar or args["时段后符"] or ""
	timeLine.format.indentSameTime=((args.indentsametime or args.ist or args["时间格式-同时缩进"])~="false")--指示同时事件缩进
	timeLine.format.title=timeTitle
	
	timeLine.format.titleLevel=tonumber(args.titlelevel or args.tl or args["标题层级"]) --若有值,则为时间线增加分标题,值为增添的层数
	if timeLine.format.titleLevel then
		timeLine.format.titleTopLevel=tonumber(args.titletop or args.ttp or args["标题顶级层级"]) or 3 --最顶级的标题层级
		timeLine.format.titleUnit=tonumber(args.titleunit or args.tu or args["标题单位"]) or 3--需要标题化的最高层级单位,默认为year
		timeLine.format.titleUnitList=mw.text.split(args.titleunits or args.tus or args["标题单位表"] or "%C;%T;%Y;%M;%D;%H",";")
		timeLine._insert=timeLine._insertTitile
	else
		timeLine.format.titleLevel=nil 
	end
	timeLine.format.split=args.sentencecontext or args.sc or args["句段连接符"] or "\n"--输出用
	timeLine.format.preTime=args.pretime or args.pt or args["时间前符"] or ""
	timeLine.format.afterTime=args.aftertime or args.at or args["时间后符"] or ","
	
	timeLine.format.cut=((args.timeformatcut or args.tfc or args["时间格式-省略"])~="false")--指示与父时间相同的步分省略
	timeLine.format.sameTimeTable={--用于识别与上一时段相同的时间--数字代表省略层级
		[0]="同期",
		["year"]="同年",
		["month"]="同月",
		["day"]="同日",
		["hour"]="同时",
		["min"]="同时",
		["second"]="同时"
	}
	timeLine.format.pattern=args.pattern or args["格式化字符串"] or "%Y%M%(Mi)%D%(Di)%H%I%S"
	timeLine.analysis.pattern= args.analysis_pattern or args.a_pattern or args["分析字符串"]
	if timeLine.analysis.pattern=="default" then
		timeLine.analysis.pattern=timeLine.format.pattern
	end

	local ignore=args.ignore or args["强制精确度"]
	if ignore=="nil" then
		timeLine.format.ignore=nil
	elseif ignore=="false" then
		timeLine.format.ignore=false
	else
		timeLine.format.ignore=true
	end
	local timeModule=module.timeModule(args)
	local totime=timeModule.toTime
	if timeLine.analysis.pattern then
		timeLine.getTime=function(text)
			return totime(text,timeLine.analysis.pattern)
		end
	else
		timeLine.getTime=totime
	end
	local time=timeModule.time
	timeLine.compareTime=setmetatable(mw.clone(time.compare),{--比较函数
		__call=function(self,timeLine1,timeLine2)
			--local bool,value=pcall( time.compare,timeLine1.time,timeLine2.time)
			return time.compare(timeLine1.time,timeLine2.time)
		end
	})
end
function module.toTimeLine(args)--转换为时间线
	module.argsSet(args)
	local root=timeLine.root()
	for _,sentence in module.preArgs(args) do
		root:insertText(sentence)
	end
	
	return root:sort()
end
function module.format(args)--函数:格式化参数table
	return module.toTimeLine(args):toArgs()
end
function module.toText(args)--函数:主要函数 转换为格式文本
	return tostring(module.toTimeLine(args))
end
function module.optionalArgsText(args)--获取可选参数文本
	local root={}
	for key,arg in pairs(args) do
		if type(key)~="number" then
			if key~="update" then
				table.insert(root,key.."="..arg)
			end
		end
	end
	return table.concat(root,"|")
end
function module.sortArgsSubst(args,name,fvalue)--返回排序参数后的模板,name指示模板名,fvalue指示sortargs的新值
	args.pre=nil
	args.after=nil
	args.pretime=nil
	args.aftertime=nil--避免重复问题
	if args.sortargs then 
		args.sortargs=fvalue
	end--置为false
	if args["排列参数"] then 
		args["排列参数"]=fvalue
	end--置为false
	local argsText=module.optionalArgsText(args)
	return "{{模板:"..name.."|"..argsText.."|\n"..module.toText(args).."\n}}"
end
function module.empty(args)--返回参数本身
	local sp=args.sentencecontext or args.sc or args["句段连接符"] or "\n"
	local t={}
	for _,arg in ipairs(args) do
		table.insert(t,arg)
	end
	return table.concat(t,sp)
end
function module._main(args, frame)--函数:主要函数
	local sortArgs=args["排列参数"] or args.sortargs or args.sort--排序参数,需要配合subst使用
	if sortArgs then
		if sortArgs=="false" then
			return module.empty(args)
		elseif sortArgs=="once" then
			return module.sortArgsSubst(args,"时间线",nil)
		else
			return module.sortArgsSubst(args,"时间线","false")
		end
	end
	return module.toText(args)
end
 
function module.main(frame)--函数:主要函数
	local args = getArgs(frame)
	return module._main(args, frame)
end

--[[function module.test()
	return module.main({"1年4月,吃饭饭","*1年2月,睡觉觉","1年4月,打豆豆","1年到1年,吃喝睡玩","同年4月,洗澡澡"})
end]]--

 
return module