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