Module:时间线
跳到导航
跳到搜索
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