--[=[ 供[[模板:生日]]使用,亦可以在其他模块中调用`from_text`、`from_month_day`两个函数 测试例: {{生日|1年2月3日}} -> 1年[[:分类:2月3日|2月3日]][[分类:2月3日]] {{生日|2月3日}} / {{生日|2|3}} -> [[:分类:2月3日|2月3日]][[分类:2月3日]] {{生日|1年<ref>……</ref>2月3日}} -> 1年<ref>……</ref>[[:分类:2月3日|2月3日]][[分类:2月3日]] {{生日|2月3日<ref>……</ref>}} -> [[:分类:2月3日|2月3日]]<ref>……</ref>[[分类:2月3日]] {{生日|2月30日}} -> 2月30日[[分类:错误生日]] {{生日|2月3.0日}} -> 2月3.0日[[分类:错误生日]] {{生日|2}} -> 2[[分类:错误生日]] {{生日|阿巴阿巴}} -> 阿巴阿巴[[分类:错误生日]] ]=] local p = {} local MAX_DAY_OF_MONTH = { -- 1 2 3 4 5 6 7 8 9 10 11 12 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } local REF_MARKER_PATTERN = '\127\'"`UNIQ%-%-[rR][eE][fF]%-%x%x%x%x%x%x%x%x%-QINU`"\'\127' local function ns0_category(category) return (mw.title.getCurrentTitle().namespace == 0) and ('[[分类:'..category..']]') or '' end local function for_hacking_template(date) return mw.getCurrentFrame():callParserFunction('#vardefine', '生日日期', date) end ---@param month string | integer ---@param day string | integer ---@return string? # 错误日期返回nil,正确日期返回分类链接和分类 local function month_day_to_wikitext(month, day) month, day = tonumber(month), tonumber(day) local max_day = MAX_DAY_OF_MONTH[month] if not (max_day and day and day >= 1 and day <= max_day) then return nil end local month_day = month..'月'..day..'日' return '[[:分类:'..month_day..'|'..month_day..']]'..ns0_category(month_day) end ---@param text string ---@param ignore_error boolean? # 错误时不添加“错误生日”分类 ---@return string function p.from_text(text, ignore_error) local var = '' repeat -- 仅执行一次,当出现错误时跳出 local prefix, month, day, suffix = text:match('^(.-)(%d+)月(%d+)日(.-)$') if not prefix then -- string库比mw.ustring更快,也因此不能写“[日号]” prefix, month, day, suffix = text:match('^(.-)(%d+)月(%d+)号(.-)$') end if not prefix then break end var = for_hacking_template(month..'月'..day..'日') if prefix ~= '' and prefix:gsub('^..-年', '', 1):gsub(REF_MARKER_PATTERN, '') ~= '' then -- “X月X日”前面的不是“X年”+任意数量的“<ref>……</ref>” break end if suffix ~= '' and suffix:gsub(REF_MARKER_PATTERN, '') ~= '' then -- “X月X日”后面的不是任意数量的“<ref>……</ref>” break end local wikitext = month_day_to_wikitext(month, day) if not wikitext then break end -- 月份或日期不合法 return var..prefix..wikitext..suffix until true if ignore_error then return var..text end return var..text..ns0_category('错误生日') end ---@param month string ---@param day string ---@param ignore_error boolean? # 错误时不添加“错误生日”分类 ---@return string function p.from_month_day(month, day, ignore_error) local result = month_day_to_wikitext(month, day) if result then return result end result = month..'月'..day..'日' if ignore_error then return result end return result..ns0_category('错误生日') end function p.main(frame) local args = frame.args local arg1, arg2 = args[1], args[2] arg1 = arg1 and mw.text.trim(arg1) if not arg1 or arg1 == '' then return '' end local ignore_error = args.ft and args.ft ~= '' arg2 = arg2 and mw.text.trim(arg2) if arg2 and arg2 ~= '' then return p.from_month_day(arg1, arg2, ignore_error) end return p.from_text(arg1, ignore_error) end function p.from_parent(frame) return p.main(frame:getParent()) end return p