利用者:Burthsceh/サンドボックス/モジュール:TimestampFormatter
local d = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
} local era = {
["明治"] = 1868, ["大正"] = 1912, ["昭和"] = 1926, ["平成"] = 1989,
} local months = {
[""] = nil,
-- roman i = 1, ii = 2, iii = 3, iiii = 4, iiv = 3, iv = 4, v = 5, vi = 6, vii = 7, viii = 8, viiii = 9, iix = 8, ix = 9, x = 10, xi = 11, xii = 12,
-- en jan = 1, january = 1, feb = 2, february = 2, mar = 3, march = 3, apr = 4, april = 4, may = 5, jun = 6, june = 6, jul = 7, july = 7, aug = 8, august = 8, sep = 9, sept = 9, september = 9, oct = 10, october = 10, nov = 11, november = 11, dec = 12, december = 12,
-- fr ["janvier"] = 1, ["février"] = 2, ["mars"] = 3, ["avril"] = 4, ["mai"] = 5, ["juin"] = 6, ["juillet"] = 7, ["août"] = 8, ["septembre"] = 9, ["octobre"] = 10, ["novembre"] = 11, ["décembre"] = 12,
} local ustr = mw.ustring local usub = ustr.sub local f = {} local p = {} local q = {} local t = {} local v = {}
function p.formatter(frame)
local timestamp = frame.args[1]; local format = frame.args[2] or "c"; local formatter = frame.args.formatter or "pf"; local validation = frame.args.validation; local debug = frame.args.debug;
return q.timestamp(timestamp, format, formatter, validation, debug)
end
function q.timestamp(timestamp, format, formatter, validation, debug)
local ts = t.generate(timestamp)
t.parse(ts) if ts.invalid then return q.error(ts, debug) .. q.categorize(ts) end
if validation then v.validate(ts) if ts.invalid then return q.error(ts, debug) .. q.categorize(ts) end end
return f[formatter](ts, format) .. q.categorize(ts)
end
function q.error(ts, debug)
local ret = " 0 then
ret = ret .. " | warning: " .. table.concat(ts.warnings, " ")
end
end
ret = ret .. "\">" .. ts.original .. ""
return ret
end
function q.categorize(ts)
local ret = ""
if ts.invalid then ret = "" end if #ts.warnings > 0 then ret = ret .. "[[Category:テンプレートを正しく使用していないページ/TimestampFormatter/" .. table.concat(ts.warnings, "]]" end
return ret
end
function t.generate(timestamp)
local ts = { era = nil, year = nil, month = nil, day = nil, yearofweek = nil, week = nil, dayofweek = nil, dayofyear = nil, hour = nil, minute = nil, second = nil, frac = nil, unixtime = false, timezone = nil, called = {}, next = "initial", position = 1, invalid = false, debug = "", warnings = {}, }
ts.original = timestamp ts.trimmed = mw.text.trim(timestamp) ts.char = mw.text.split(ts.trimmed, "") ts.length = #ts.char ts.size = #ts.trimmed
return ts
end
function t.parse(ts)
repeat table.insert(ts.called, ts.next) t[ts.next](ts) until ts.next == nil or ts.length < ts.position
end
function t.initial(ts)
if ts.length < 4 then ts.next = nil ts.invalid = true return end
local c1 = ts.char[1] local c2 = ts.char[2]
if "0" <= c1 and c1 <= "9" then ts.next = "numeric" elseif c1 == "+" or c1 == "-" then ts.next = "拡大" elseif c1 == "@" then ts.next = "unixtime" elseif ("A" <= c1 and c1 <= "Z") or ("a" <= c1 and c1 <= "z") then ts.next = "alphabet" elseif c1 == "平" and c2 == "成" then ts.era = "平成" ts.next = "日時元号" ts.position = 3 elseif c1 == "昭" and c2 == "和" then ts.era = "昭和" ts.next = "日時元号" ts.position = 3 elseif c1 == "明" and c2 == "治" then ts.era = "明治" ts.next = "日時元号" ts.position = 3 elseif c1 == "大" and c2 == "正" then ts.era = "大正" ts.next = "日時元号" ts.position = 3 else ts.next = nil ts.invalid = true end
end
t.unixtime = function (ts)
if string.match(ts.trimmed, "^@%-?[0-9]+$") then ts.unixtime = true else ts.invalid = true end ts.next = nil
end
t.numeric = function (ts)
local numend = 1 while numend <= ts.length and "0" <= ts.char[numend] and ts.char[numend] <= "9" do numend = numend + 1 end
numend = numend - 1
if numend == ts.length then ts.next = nil if numend <= 8 then -- 4 <= numend ts.year = tonumber(usub(ts.trimmed, 1, 4)) if numend == 5 then ts.month = tonumber(ts.char[5]) elseif numend == 6 then ts.month = tonumber(ts.char[5] .. ts.char[6]) elseif numend == 7 then ts.dayofyear = tonumber(usub(ts.trimmed, 5, 7)) elseif numend == 8 then ts.month = tonumber(ts.char[5] .. ts.char[6]) ts.day = tonumber(ts.char[7] .. ts.char[8]) end elseif numend == 14 then ts.year = tonumber(usub(ts.trimmed, 1, 4)) ts.month = tonumber(ts.char[5] .. ts.char[6]) ts.day = tonumber(ts.char[7] .. ts.char[8]) ts.hour = tonumber(ts.char[9] .. ts.char[10]) ts.minute = tonumber(ts.char[11] .. ts.char[12]) ts.second = tonumber(ts.char[13] .. ts.char[14]) elseif numend == 13 then ts.year = tonumber(usub(ts.trimmed, 1, 4)) ts.dayofyear = tonumber(usub(ts.trimmed, 5, 7)) ts.hour = tonumber(ts.char[8] .. ts.char[9]) ts.minute = tonumber(ts.char[10] .. ts.char[11]) ts.second = tonumber(ts.char[12] .. ts.char[13]) else ts.invalid = true end else if numend == 4 then if ts.length < 6 then ts.next = nil ts.invalid = true end local c5 = ts.char[5] local c6 = ts.char[6] if c5 == "-" then if "0" <= c6 and c6 <= "9" then ts.next = "拡張" elseif c6 == "W" then ts.yearofweek = tonumber(usub(ts.trimmed, 1, 4)) ts.next = "拡大W" ts.position = 6 else ts.next = "YYYYMonth" end elseif c5 == "年" or c5 == "(" or c5 == "(" then ts.next = "日時数字" elseif c5 == "/" then ts.next = "slash" elseif c5 == "W" then if string.match(ts.trimmed, "^@[0-9][0-9][0-9][0-9]W[0-5][0-9][1-7][0-2][0-9][0-5][0-9][0-5][0-9]$") then
ts.yearofweek = tonumber(usub(ts.trimmed, 1, 4)) ts.week = tonumber(ts.char[6] .. ts.char[7]) ts.dayofweek = tonumber(ts.char[8]) ts.hour = tonumber(ts.char[9] .. ts.char[10]) ts.minute = tonumber(ts.char[11] .. ts.char[12]) ts.second = tonumber(ts.char[13] .. ts.char[14]) ts.next = nil else ts.next = "基本W" end else ts.next = "YYYYMonth" end elseif numend == 1 then ts.next = "dMonthYYYY" ts.position = 1 elseif numend == 2 then ts.position = 2 if ts.length == 26 and ts.size == 26 then ts.next = "Common Log Format" else ts.next = "dMonthYYYY" end elseif numend == 7 then ts.year = tonumber(usub(ts.trimmed, 1, 4)) ts.dayofyear = tonumber(usub(ts.trimmed, 5, 7)) ts.next = "基本time" ts.position = 8 elseif numend == 8 then ts.year = tonumber(usub(ts.trimmed, 1, 4)) ts.month = tonumber(ts.char[5] .. ts.char[6]) ts.day = tonumber(ts.char[7] .. ts.char[8]) ts.next = "基本time" ts.position = 9 else ts.next = nil ts.invalid = true end end
end
t.alphabet = function(ts)
ts.next = "Monthd?YYYY"
end
-- [ISO 8601[
t["基本W"] = function (ts)
ts.yearofweek = tonumber(usub(ts.trimmed, 1, 4)) local p = ts.position if ts.length ~= ts.size or ts.length < 7 or ts.char[6] < "0" or "9" < ts.char[6] or ts.char[7] < "0" or "9" < ts.char[7] then
ts.next = nil ts.invalid = true end
ts.week = tonumber(ts.char[p] .. ts.char[p+1])
if ts.length == 7 then ts.next = nil elseif "1" <= ts.char[8] and ts.char[8] <= "7" then ts.dayofweek = tonumber(ts.char[8]) ts.position = 9 ts.next = "基本time" else ts.next = nil ts.invalid = true end
end
t["基本time"] = function (ts)
local p = ts.position if ts.length ~= ts.size or ts.length < p + 2 or ts.char[p] ~= "T" then ts.next = nil ts.invalid = true return end
local numend = 1 while p + numend <= ts.length and "0" <= ts.char[p+numend] and ts.char[p+numend] <= "9" do numend = numend + 1 end numend = numend - 1
if not (numend == 6 or numend == 4 or numend == 2) then ts.next = nil ts.invalid = true return end
ts.next = "基本残り" ts.hour = tonumber(ts.char[p+1] .. ts.char[p+2]) if numend == 2 then ts.position = p + 3 return end
ts.minute = tonumber(ts.char[p+3] .. ts.char[p+4]) if numend == 4 then ts.position = p + 5 else ts.second = tonumber(ts.char[p+5] .. ts.char[p+6]) ts.position = p + 7 end
end
t["基本残り"] = function (ts)
local p = ts.position if ts.char[p] == "." or ts.char[p] == "," then repeat p = p + 1 until p <= ts.length and "0" <= ts.char[p] and ts.char[p] <= "9" ts.frac = tonumber("0." .. usub(ts.trimmed, ts.position, p - 1))
if ts.minute == nil then local t = ts.frac * 60 ts.minute = math.floor(t) ts.frac = t - ts.minute end if ts.second == nil then local t = ts.frac * 60 ts.second = math.floor(t) ts.frac = t - ts.second end if ts.length == p - 1 then ts.next = nil return end end
if ts.char[p] == "+" or ts.char[p] == "-" then if ts.length == p + 2 and ts.char[p+1] == "0" or ts.char[p+1] == "1" and "0" <= ts.char[p+2] and ts.char[p+2] <= "9" then
ts.timezone = usub(ts.trimmed, p, p + 2) elseif ts.length == p + 4 and ts.char[p+1] == "0" or ts.char[p+1] == "1" and "0" <= ts.char[p+2] and ts.char[p+2] <= "9" and "0" <= ts.char[p+3] and ts.char[p+3] <= "5" and "0" <= ts.char[p+4] and ts.char[p+4] <= "9" then
ts.timezone = usub(ts.trimmed, p, p + 4) else ts.invalid = true end elseif ts.char[p] == "Z" then ts.timezone = "Z" else ts.invalid = true end
ts.next = nil
end
t["拡張"] = function (ts)
ts.year = tonumber(usub(ts.trimmed, 1, 4))
if ts.length ~= ts.size then ts.next = nil ts.invalid = true return elseif ts.length == 6 then ts.month = tonumber(ts.char[6]) ts.next = nil return elseif ts.char[7] == "-" then ts.next = "拡張独自M" return elseif ts.char[7] < "0" or "9" < ts.char[7] then ts.next = nil ts.invalid = true return end
if ts.length == 7 then ts.month = tonumber(ts.char[6] .. ts.char[7]) ts.next = nil elseif ts.length == 8 then ts.next = "拡大DDD" ts.position = 6 elseif ts.char[8] == "-" then ts.next = "拡張MM" else ts.next = "拡大DDD" ts.position = 6 end
end
t["拡張MM"] = function (ts)
ts.month = tonumber(ts.char[6] .. ts.char[7])
if ts.length == 9 then ts.next = nil if "0" <= ts.char[9] and ts.char[9] <= "9" then ts.day = tonumber(ts.char[9]) else ts.invalid = true end elseif "0" <= ts.char[9] and ts.char[9] <= "9" then if "0" <= ts.char[10] and ts.char[10] <= "9" then ts.day = tonumber(ts.char[9] .. ts.char[10]) if ts.length == 10 then ts.next = nil elseif ts.char[11] == "T" then ts.next = "拡張time" ts.position = 12 elseif ts.char[11] == " " then ts.next = "拡張time" ts.debug = "独自" ts.position = 12 else ts.next = nil ts.invalid = true end else ts.day = tonumber(ts.char[9]) if ts.length == 10 then ts.next = nil ts.invalid = true elseif ts.char[10] == " " or ts.char[10] == "T" then ts.next = "拡張time" ts.debug = "独自" ts.position = 11 else ts.next = nil ts.invalid = true end end end
end
t["拡張独自M"] = function (ts)
if ts.length < 8 or ts.char[8] < "0" or "9" < ts.char[8] then ts.next = nil ts.invalid = true return end
ts.month = tonumber(ts.char[6])
if ts.length == 8 then ts.day = tonumber(ts.char[8]) ts.next = nil elseif ts.char[9] == " " or ts.char[9] == "T" then ts.day = tonumber(ts.char[8]) ts.next = "拡張time" ts.debug = "独自" ts.position = 10 elseif "0" <= ts.char[9] and ts.char[9] <= "9" then ts.day = tonumber(ts.char[8] .. ts.char[9]) if ts.length == 9 then ts.next = nil elseif ts.char[10] == " " or ts.char[10] == "T" then ts.next = "拡張time" ts.debug = "独自" ts.position = 11 else ts.next = nil ts.invalid = true end end
end
t["拡張time"] = function (ts)
local p = ts.position if ts.length < p + 3 or ts.char[p] < "0" or "9" < ts.char[p] then ts.next = nil ts.debug = "0" ts.invalid = true return end
if "0" <= ts.char[p+1] and ts.char[p+1] <= "9" then ts.hour = tonumber(ts.char[p] .. ts.char[p+1]) if ts.char[p+2] ~= ":" then ts.next = nil ts.invalid = true ts.debug = "1" return end p = p + 3 elseif ts.char[p+1] == ":" then ts.hour = tonumber(ts.char[p]) p = p + 2 else ts.next = nil ts.invalid = true ts.debug = "2" return end
if p + 1 <= ts.length and "0" <= ts.char[p] and ts.char[p] <= "9" and "0" <= ts.char[p+1] and ts.char[p+1] <= "9" then
ts.minute = tonumber(ts.char[p] .. ts.char[p+1]) else ts.next = nil ts.invalid = true ts.debug = "3" return end
p = p + 2
if p + 2 <= ts.length and ts.char[p] == ":" and "0" <= ts.char[p+1] and ts.char[p+1] <= "9" and "0" <= ts.char[p+2] and ts.char[p+2] <= "9" then
ts.second = tonumber(ts.char[p+1] .. ts.char[p+2]) p = p + 3 end if ts.debug ~= "独自" and (p == 17 or p == 20) then ts.next = "拡大残り" else ts.next = "timezone" end ts.position = p
end
-- 年拡大 t["拡大"] = function (ts)
if ts.length ~= ts.size then ts.next = nil ts.invalid = true return end
local yearend = 2 while yearend <= ts.length and "0" <= ts.char[yearend] and ts.char[yearend] <= "9" do yearend = yearend + 1 end
if yearend < 6 then ts.next = nil ts.invalid = true ts.debug = "1:" .. yearend return end
ts.position = yearend + 1 yearend = yearend - 1
if ts.length == yearend then ts.year = tonumber(usub(ts.trimmed, 1, yearend)) ts.next = nil ts.debug = "3" elseif ts.length < yearend + 3 or ts.char[yearend+1] ~= "-" then ts.next = nil ts.invalid = true ts.debug = "4" elseif ts.char[yearend+2] == "W" then ts.yearofweek = tonumber(usub(ts.trimmed, 1, yearend)) ts.next = "拡大W" else ts.year = tonumber(usub(ts.trimmed, 1, yearend)) if yearend + 4 <= ts.length and "0" <= ts.char[yearend+4] and ts.char[yearend+4] <= "9" then ts.next = "拡大DDD" else ts.next = "拡大MMDD" end end
end
t["拡大DDD"] = function (ts)
local dddstart = ts.position if "0" <= ts.char[dddstart] and ts.char[dddstart] <= "9" and "0" <= ts.char[dddstart+1] and ts.char[dddstart+1] <= "9" and "0" <= ts.char[dddstart+2] and ts.char[dddstart+2] <= "9" then
ts.dayofyear = tonumber(usub(ts.trimmed, dddstart, dddstart + 2)) ts.position = dddstart + 3 ts.next = "拡大time" else ts.next = nil ts.invalid = true end
end
t["拡大MMDD"] = function (ts)
local p = ts.position if "0" <= ts.char[p] and ts.char[p] <= "9" and "0" <= ts.char[p+1] and ts.char[p+1] <= "9" then
ts.month = tonumber(ts.char[p] .. ts.char[p+1]) else ts.next = nil ts.invalid = true return end
p = p + 2
if ts.length < p then ts.next = nil elseif ts.char[p] ~= "-" or ts.length < p + 1 then ts.next = nil ts.invalid = true else ts.day = tonumber(ts.char[p+1] .. ts.char[p+2]) ts.position = p + 3 ts.next = "拡大time" end
end
t["拡大W"] = function (ts)
local p = ts.position + 1 if p + 1 <= ts.length and "0" <= ts.char[p] and ts.char[p] <= "9" and "0" <= ts.char[p+1] and ts.char[p+1] <= "9" then
ts.week = tonumber(ts.char[p] .. ts.char[p+1]) else ts.next = nil ts.invalid = true return end
p = p + 2
if ts.length < p then ts.next = nil elseif ts.char[p] ~= "-" or ts.length < p + 1 then ts.next = nil ts.invalid = true elseif "1" <= ts.char[p+1] and ts.char[p+1] <= "7" then ts.dayofweek = tonumber(ts.char[p+1]) ts.position = p + 2 ts.next = "拡大time" else ts.next = nil ts.invalid = true end
end
t["拡大time"] = function (ts)
local p = ts.position if ts.char[p] ~= "T" or ts.length < p + 5 or ts.char[p+3] ~= ":" then ts.next = nil ts.invalid = true ts.debug = "0: " .. p return end
p = p + 1
if "0" <= ts.char[p] and ts.char[p] <= "9" and "0" <= ts.char[p+1] and ts.char[p+1] <= "9" then
ts.hour = tonumber(ts.char[p] .. ts.char[p+1]) else ts.next = nil ts.invalid = true ts.debug = "1" return end
p = p + 3
if "0" <= ts.char[p] and ts.char[p] <= "9" and "0" <= ts.char[p+1] and ts.char[p+1] <= "9" then
ts.minute = tonumber(ts.char[p] .. ts.char[p+1]) else ts.next = nil ts.invalid = true ts.debug = "2" return end
p = p + 2
if ts.length < p then ts.next = nil ts.debug = "3" elseif p + 2 <= ts.length and ts.char[p] == ":" and "0" <= ts.char[p+1] and ts.char[p+1] <= "9" and "0" <= ts.char[p+2] and ts.char[p+2] <= "9" then
ts.second = tonumber(ts.char[p+1] .. ts.char[p+2])
p = p + 3 ts.debug = "4" else ts.debug = "5" end ts.next = "拡大残り" ts.position = p
end
t["拡大残り"] = function (ts)
local p = ts.position if ts.char[p] == "." or ts.char[p] == "," then repeat p = p + 1 until p <= ts.length and "0" <= ts.char[p] and ts.char[p] <= "9" ts.frac = tonumber("0." .. usub(ts.trimmed, ts.position, p - 1))
if ts.second == nil then local t = ts.frac * 60 ts.second = math.floor(t) ts.frac = t - ts.second end if ts.length == p - 1 then ts.next = nil return end end
if ts.char[p] == "+" or ts.char[p] == "-" then if ts.length == p + 2 and ts.char[p+1] == "0" or ts.char[p+1] == "1" and "0" <= ts.char[p+2] and ts.char[p+2] <= "9" then
ts.timezone = usub(ts.trimmed, p, p + 2) elseif ts.length == p + 5 and ts.char[p+1] == "0" or ts.char[p+1] == "1" and "0" <= ts.char[p+2] and ts.char[p+2] <= "9" and ts.char[p+3] == ":" and "0" <= ts.char[p+4] and ts.char[p+4] <= "5" and "0" <= ts.char[p+5] and ts.char[p+5] <= "9" then
ts.timezone = usub(ts.trimmed, p, p + 5) else ts.invalid = true end elseif ts.char[p] == "Z" then ts.timezone = "Z" else ts.invalid = true end
ts.next = nil
end
-- ]ISO 8601]
-- [en[
--ymd t.YYYYMonth = function (ts)
ts.year = tonumber(usub(ts.trimmed, 1, 4)) local t = ustr.match(usub(ts.trimmed, 5), "^[\t\n\f\r ,-.]*(.-)$") local month = ustr.lower(ustr.match(t, "^%a+") or "") ts.month = months[month] if ts.month == nil then ts.next = nil ts.invalid = true return end t = ustr.match(string.sub(t, #month + 1), "^[\t\n\f\r ,-.]*(.-)$") if #t == 0 then ts.next = nil return end ts.day = string.match(t, "^[0-9]+") if ts.day == nil then ts.next = nil ts.invalid = true return end t = ustr.match(string.sub(t, #ts.day + 1), "^[nrst]?[dht]?[\t\n\f\r ,-.at]*(.-)$") ts.day = tonumber(ts.day) if #t == 0 then ts.next = nil else ts.next = "time" ts.position = ts.length - ustr.len(t) + 1 end
end
--dmy t.dMonthYYYY = function (ts)
local p = ts.position ts.day = tonumber(usub(ts.trimmed, 1, p)) local t = ustr.match(usub(ts.trimmed, p + 1), "^[nrst]?[dht]?[\t\n\f\r ,-.]*(.-)$") local month = ustr.lower(ustr.match(t, "^%a+") or "") ts.month = months[month] if ts.month == nil then ts.next = nil ts.invalid = true return end t = ustr.match(string.sub(t, #month + 1), "^[\t\n\f\r ,-.]*(.-)$") if #t == 0 then ts.next = nil ts.invalid = true return end ts.year = string.match(t, "^[0-9]+") if ts.year == nil then ts.next = nil ts.invalid = true return end t = ustr.match(string.sub(t, #ts.year + 1), "^[\t\n\f\r ,-.at]*(.-)$") ts.year = tonumber(ts.year) if #t == 0 then ts.next = nil else ts.next = "time" ts.position = ts.length - ustr.len(t) + 1 end
end
--mdy t["Monthd?YYYY"] = function (ts)
local a = ustr.lower(ustr.match(ts.trimmed, "^%a+") or "") ts.month = months[a] if ts.month == nil then ts.next = nil ts.invalid = true return end local t = ustr.match(string.sub(ts.trimmed, #a + 1), "^[\t\n\f\r ,-.]*(.-)$") if #t == 0 then ts.next = nil ts.invalid = true return end a = string.match(t, "^[0-9]+") if a == nil or #a == 3 then ts.next = nil ts.invalid = true return elseif #a > 3 then ts.year = tonumber(a) ts.next = nil return end ts.day = tonumber(a) t = ustr.match(usub(t, #a + 1), "^[nrst]?[dht]?[\t\n\f\r ,-.]*(.-)$") if #t == 0 then ts.next = nil ts.invalid = true return end ts.year = string.match(t, "^[0-9]+") if ts.year == nil then ts.next = nil ts.invalid = true return end t = ustr.match(string.sub(t, #ts.year + 1), "^[\t\n\f\r ,-.at]*(.-)$") ts.year = tonumber(ts.year) if #t == 0 then ts.next = nil else ts.next = "time" ts.position = ts.length - ustr.len(t) + 1 end
end
t.time = function (ts)
local p = ts.position if ts.length < p + 3 or ts.char[p] < "0" or "9" < ts.char[p] then ts.next = nil ts.invalid = true ts.debug = "0" return end
if "0" <= ts.char[p+1] and ts.char[p+1] <= "9" then ts.hour = tonumber(ts.char[p] .. ts.char[p+1]) if ts.char[p+2] ~= ":" then ts.next = nil ts.invalid = true ts.debug = "1" return end p = p + 3 elseif ts.char[p+1] == ":" then ts.hour = tonumber(ts.char[p]) p = p + 2 else ts.next = nil ts.invalid = true ts.debug = "2" return end
if ts.length >= p + 1 and "0" <= ts.char[p] and ts.char[p] <= "9" and "0" <= ts.char[p+1] and ts.char[p+1] <= "9" then
ts.minute = tonumber(ts.char[p] .. ts.char[p+1]) else ts.next = nil ts.invalid = true ts.debug = "3" return end
p = p + 2
if p + 2 <= ts.length then if ts.char[p] == ":" and "0" <= ts.char[p+1] and ts.char[p+1] <= "9" and "0" <= ts.char[p+2] and ts.char[p+2] <= "9" then
ts.second = tonumber(ts.char[p+1] .. ts.char[p+2]) p = p + 3 end local ap = ustr.match(usub(ts.trimmed, p), "^[\t\n\f\r ,-.]*([APap]).?[Mm].?") if ap then p = p + ustr.len(ustr.match(usub(ts.trimmed, p), "^[\t\n\f\r ,-.]*[APap].?[Mm].?")) if ap == "P" or ap == "p" then ts.hour = ts.hour + 12 end end end ts.next = "timezone" ts.position = p
end
-- ]en]
t.slash = function (ts)
if ts.length ~= ts.size or ts.length < 6 or ts.char[6] < "0" or "9" < ts.char[6] then ts.next = "日時数字" return end ts.year = tonumber(usub(ts.trimmed, 1, 4)) if ts.length == 6 then ts.month = tonumber(ts.char[6]) ts.next = nil return end local p = 9 if "0" <= ts.char[7] or ts.char[7] <= "9" then ts.month = tonumber(ts.char[6] .. ts.char[7]) if ts.length == 7 then ts.next = nil return elseif ts.char[8] ~= "/" then ts.next = nil ts.invalid = true end elseif ts.char[7] == "/" then ts.month = tonumber(ts.char[6]) p = 8 else ts.next = nil ts.invalid = true return end if ts.length < p or ts.char[p] < "0" or "9" < ts.char[p] then ts.next = nil ts.invalid = true elseif ts.length == p then ts.day = tonumber(ts.char[p]) ts.next = nil elseif "0" <= ts.char[p+1] or ts.char[p+1] <= "9" then ts.day = tonumber(ts.char[p] .. ts.char[p+1]) if ts.length == p + 1 then ts.next = nil elseif ts.length < p + 6 then ts.next = nil ts.invalid = true elseif ts.char[p+2] == " " then ts.next = "time" ts.position = p + 3 end end
end
t["Common Log Format"] = function (ts)
if not string.match(ts.trimmed, "^[0-3][0-9]/[ADFJMNOS][aceopu][bcglnprtvy]/[0-9][0-9][0-9][0-9]:[0-2][0-9]:[0-5][0-9]:[0-6][0-9] [%+%-][01][0-9][0-5][0-9]$") then
ts.next = "dMonthYYYY" return end
local Mon = { Jan = 1, Feb = 2, Mar = 3, Apr = 4, May = 5, Jun = 6, Jul = 7, Aug = 8, Sep = 9, Oct = 10, Nov = 11, Dec = 12, } ts.year = tonumber(usub(ts.trimmed, 8, 11)) ts.month = Mon[usub(ts.trimmed, 4, 6)] if ts.month == nil then ts.year = nil ts.next = "dMonthYYYY" return end ts.day = tonumber(ts.char[1] .. ts.char[2]) ts.hour = tonumber(ts.char[13] .. ts.char[14]) ts.minute = tonumber(ts.char[16] .. ts.char[17]) ts.second = tonumber(ts.char[19] .. ts.char[20]) ts.timezone = usub(ts.trimmed, 21, 26) ts.next = nil
end
t.timezone = function (ts)
ts.next = nil local t = mw.text.trim(usub(ts.trimmed, ts.position), "\t\n\f\r ()") if #t ~= ustr.len(t) then ts.invalid = true elseif string.match(t, "^[A-Za-z]+$") then if 1 <= #t and #t <= 6 then ts.timezone = t else ts.invalid = true end elseif string.match(t, "^[%+%-][01][0-9]$") then ts.timezone = t elseif string.match(t, "^[%+%-][01][0-9]:?[0-5][0-9]$") then ts.timezone = t elseif string.match(t, "^GMT[%+%-][01][0-9]$") then ts.timezone = t elseif string.match(t, "^GMT[%+%-][01][0-9]:?[0-5][0-9]$") then ts.timezone = t elseif string.match(t, "^UTC[%+%-][01][0-9]$") then ts.timezone = string.sub(t, 4) elseif string.match(t, "^UTC[%+%-][01][0-9]:?[0-5][0-9]$") then ts.timezone = string.sub(t, 4) else local s, e = string.find(t, "^[A-Z][a-z]+") if s then s = string.sub(t, e + 1) e = string.sub(t, 1, e) for a in string.gmatch(s, "[_/][A-Z][a-z]+") do e = e .. a end if t == e then ts.timezone = t else ts.invalid = true end else ts.invalid = true end end
end
-- [ja[
local tokennumber = {
["0"] = "number", ["1"] = "number", ["2"] = "number", ["3"] = "number", ["4"] = "number", ["5"] = "number", ["6"] = "number", ["7"] = "number", ["8"] = "number", ["9"] = "number",
} local tokenpunc = {
["\t"] = "punc", ["\n"] = "punc", ["\f"] = "punc", ["\r"] = "punc", [" "] = "punc", [","] = "punc", ["-"] = "punc", ["/"] = "punc", [" "] = "punc", ["、"] = "punc", ["。"] = "punc", [","] = "punc", ["."] = "punc",
} local token1 = {
["("] = "open", ["("] = "open", [")"] = "close", [")"] = "close", ["元"] = "元", ["年"] = "年", ["月"] = "月", ["日"] = "日", ["時"] = "時", ["分"] = "分", ["秒"] = "秒",
} local token2 = {
["午前"] = "午", ["午後"] = "午", ["日曜"] = "曜日", ["月曜"] = "曜日", ["火曜"] = "曜日", ["水曜"] = "曜日", ["木曜"] = "曜日", ["金曜"] = "曜日", ["土曜"] = "曜日", ["明治"] = "元号", ["大正"] = "元号", ["昭和"] = "元号", ["平成"] = "元号",
} local token3 = {
["(日)"] = "曜日", ["(月)"] = "曜日", ["(火)"] = "曜日", ["(水)"] = "曜日", ["(木)"] = "曜日", ["(金)"] = "曜日", ["(土)"] = "曜日", ["(日)"] = "曜日", ["(月)"] = "曜日", ["(火)"] = "曜日", ["(水)"] = "曜日", ["(木)"] = "曜日", ["(金)"] = "曜日", ["(土)"] = "曜日", ["日曜日"] = "曜日", ["月曜日"] = "曜日", ["火曜日"] = "曜日", ["水曜日"] = "曜日", ["木曜日"] = "曜日", ["金曜日"] = "曜日", ["土曜日"] = "曜日",
} local dayofweek = {
["(日)"] = 1, ["(月)"] = 2, ["(火)"] = 3, ["(水)"] = 4, ["(木)"] = 5, ["(金)"] = 6, ["(土)"] = 7, ["(日)"] = 1, ["(月)"] = 2, ["(火)"] = 3, ["(水)"] = 4, ["(木)"] = 5, ["(金)"] = 6, ["(土)"] = 7, ["日曜"] = 1, ["月曜"] = 2, ["火曜"] = 3, ["水曜"] = 4, ["木曜"] = 5, ["金曜"] = 6, ["土曜"] = 7, ["日曜日"] = 1, ["月曜日"] = 2, ["火曜日"] = 3, ["水曜日"] = 4, ["木曜日"] = 5, ["金曜日"] = 6, ["土曜日"] = 7,
-- zh ["(一)"] = 2, ["(二)"] = 3, ["(三)"] = 4, ["(四)"] = 5, ["(五)"] = 6, ["(六)"] = 7, ["(七)"] = 1, -- ["(天)"] = 1, ["(一)"] = 2, ["(二)"] = 3, ["(三)"] = 4, ["(四)"] = 5, ["(五)"] = 6, ["(六)"] = 7, ["(七)"] = 1, -- ["(天)"] = 1, ["星期一"] = 2, ["星期二"] = 3, ["星期三"] = 4, ["星期四"] = 5, ["星期五"] = 6, ["星期六"] = 7, ["星期七"] = 1, -- ["星期天"] = 1, ["星期日"] = 1, ["礼拜一"] = 2, ["礼拜二"] = 3, ["礼拜三"] = 4, ["礼拜四"] = 5, ["礼拜五"] = 6, ["礼拜六"] = 7, ["礼拜七"] = 1, -- ["礼拜天"] = 1, ["礼拜日"] = 1, ["礼拝一"] = 2, -- ["礼拝二"] = 3, -- ["礼拝三"] = 4, -- ["礼拝四"] = 5, -- ["礼拝五"] = 6, -- ["礼拝六"] = 7, -- ["礼拝七"] = 1, -- ["礼拝天"] = 1, -- ["礼拝日"] = 1, --
}
t["日時数字"] = function (ts)
local state = { { "number|year", { call = "元号", "open", "元号", "number", "close", }, "年", { call = "元号", "open", "元号", "number", "年", "close", }, }, { "number|month", "月", }, { "number|day", "日", { call = "曜日", "曜日", }, }, { { call = "午", "午", }, "number|hour", "時", { call = "分秒",--[[ "number|minute", "分", { "number|second", "秒", },]] }, }, } local token1 = { ["("] = "open", ["("] = "open", [")"] = "close", [")"] = "close", ["元"] = "元", ["年"] = "年", ["月"] = "月", ["日"] = "日", ["号"] = "日", -- zh ["時"] = "時", ["分"] = "分", ["秒"] = "秒", } local token3 = { ["(日)"] = "曜日", ["(月)"] = "曜日", ["(火)"] = "曜日", ["(水)"] = "曜日", ["(木)"] = "曜日", ["(金)"] = "曜日", ["(土)"] = "曜日", ["(日)"] = "曜日", ["(月)"] = "曜日", ["(火)"] = "曜日", ["(水)"] = "曜日", ["(木)"] = "曜日", ["(金)"] = "曜日", ["(土)"] = "曜日", ["日曜日"] = "曜日", ["月曜日"] = "曜日", ["火曜日"] = "曜日", ["水曜日"] = "曜日", ["木曜日"] = "曜日", ["金曜日"] = "曜日", ["土曜日"] = "曜日",
-- zh ["(一)"] = "曜日", ["(二)"] = "曜日", ["(三)"] = "曜日", ["(四)"] = "曜日", ["(五)"] = "曜日", ["(六)"] = "曜日", ["(七)"] = "曜日", ["(天)"] = "曜日", ["(一)"] = "曜日", ["(二)"] = "曜日", ["(三)"] = "曜日", ["(四)"] = "曜日", ["(五)"] = "曜日", ["(六)"] = "曜日", ["(七)"] = "曜日", ["(天)"] = "曜日", ["星期一"] = "曜日", ["星期二"] = "曜日", ["星期三"] = "曜日", ["星期四"] = "曜日", ["星期五"] = "曜日", ["星期六"] = "曜日", ["星期七"] = "曜日", ["星期天"] = "曜日", ["星期日"] = "曜日", ["礼拜一"] = "曜日", ["礼拜二"] = "曜日", ["礼拜三"] = "曜日", ["礼拜四"] = "曜日", ["礼拜五"] = "曜日", ["礼拜六"] = "曜日", ["礼拜七"] = "曜日", ["礼拜天"] = "曜日", ["礼拜日"] = "曜日", ["礼拝一"] = "曜日", ["礼拝二"] = "曜日", ["礼拝三"] = "曜日", ["礼拝四"] = "曜日", ["礼拝五"] = "曜日", ["礼拝六"] = "曜日", ["礼拝七"] = "曜日", ["礼拝天"] = "曜日", ["礼拝日"] = "曜日", } local str = ts.char local point = 0
function scan() local val = "" local type = "" if ts.length <= point then return "end", nil end while point < ts.length and type do point = point + 1 type = tokenpunc[str[point]] end if point + 2 <= ts.length then val = str[point] .. str[point+1] .. str[point+2] type = token3[val] if type then point = point + 2 return type, val end end if point + 1 <= ts.length then val = str[point] .. str[point+1] type = token2[val] if type then point = point + 1 return type, val end end if point <= ts.length then val = str[point] type = token1[val] if type then return type, val end end type = tokennumber[str[point]] if type == nil then return "error", nil end val = str[point] while point < ts.length do point = point + 1 type = tokennumber[str[point]] if type == nil then point = point - 1 return "number", tonumber(val) end val = val .. str[point] end return "end", nil end
local u = {}
u["元号"] = function (v2) local p = point
local t, v, e for i3, v3 in ipairs(v2) do t, v = scan() if v3 == t then if t == "元号" then e = v elseif t == "number" then if e == "明治" then if ts.year > 1872 then if v + 1867 ~= ts.year then table.insert(ts.warnings, "年不一致") return false end end elseif v + era[e] - 1 ~= ts.year then table.insert(ts.warnings, "年不一致") return false end end elseif v3 == "number" and t == "元" then if e ~= "明治" and era[e] ~= ts.year then table.insert(ts.warnings, "年不一致") return false end elseif v3 == "open" then point = p return true else ts.debug = v3 .. t .. point return false end end return true end
u["曜日"] = function (v2) local p = point local t, v = scan() if t == "曜日" then ts.dayofweek = dayofweek[v] else point = p end return true end
local pm = false u["午"] = function (v2) local p = point local t, v = scan() if t == "午" then if v == "午後" then pm = true end else point = p end return true end
u["分秒"] = function (v2) local p = point local t, v = scan() if t == "number" then ts.minute = v else point = p ts.next = "timezone" if pm then ts.hour = ts.hour + 12 end ts.position = p + 1 return nil end t, v = scan() if t ~= "分" then point = p ts.next = "timezone" if pm then ts.hour = ts.hour + 12 end ts.position = p + 1 return nil end p = point t, v = scan() if t == "number" then ts.second = v else point = p ts.next = "timezone" if pm then ts.hour = ts.hour + 12 end ts.position = p + 1 return nil end t, v = scan() if t ~= "秒" then point = p ts.next = "timezone" if pm then ts.hour = ts.hour + 12 end ts.position = p + 1 return nil end return true end
if not ustr.match(ts.trimmed, "時") then table.remove(state) end
local t, v for i1, v1 in ipairs(state) do for i2, v2 in ipairs(v1) do if type(v2) == "table" then local z = u[v2.call](v2) if z == false then ts.next = nil ts.invalid = true return elseif z == nil then return end else local v21, v22 = unpack(mw.text.split(v2, "|", true)) t, v = scan() if v21 == t then if v22 then ts[v22] = v end elseif t == "end" and v21 == "number" then ts.next = nil if pm then ts.hour = ts.hour + 12 end return else ts.next = nil ts.invalid = true ts.debug = v2 .. t .. point .. tostring(v) .. v21 return end end end end
if ustr.match(ts.trimmed, "時") then if pm then ts.hour = ts.hour + 12 end ts.next = "timezone" ts.position = point + 1 else ts.next = "time" ts.position = point + 1 + ustr.len(ustr.match(usub(ts.trimmed, point + 1), "^[\t\n\f\r ,-.]*")) end
end
t["日時元号"] = function (ts)
ts.position = 3 if ustr.match(ts.trimmed, "[0-9]") then ts.next = "日時元号数字" elseif ustr.match(ts.trimmed, "[0-9]") then local s = ustr.gsub(ts.trimmed, "0", "0") s = ustr.gsub(s, "1", "1") s = ustr.gsub(s, "2", "2") s = ustr.gsub(s, "3", "3") s = ustr.gsub(s, "4", "4") s = ustr.gsub(s, "5", "5") s = ustr.gsub(s, "6", "6") s = ustr.gsub(s, "7", "7") s = ustr.gsub(s, "8", "8") ts.trimmed = ustr.gsub(s, "9", "9") ts.char = mw.text.split(ts.trimmed, "") ts.next = "日時元号数字" elseif ustr.match(ts.trimmed, "[零〇]") then local s = ustr.gsub(ts.trimmed, "零", "〇") s = ustr.gsub(s, "[弌壱壹]", "一") s = ustr.gsub(s, "[弍弐貮貳贰]", "二") s = ustr.gsub(s, "[弎参參叁]", "三") s = ustr.gsub(s, "肆", "四") s = ustr.gsub(s, "伍", "五") s = ustr.gsub(s, "[陸陆]", "六") s = ustr.gsub(s, "[柒漆質]", "七") s = ustr.gsub(s, "捌", "八") ts.trimmed = ustr.gsub(s, "玖", "九") ts.char = mw.text.split(ts.trimmed, "") ts.next = "日時元号漢字位取り" elseif ustr.match(ts.trimmed, "[十拾廿念百陌佰千阡仟万萬]") then local s = ustr.gsub(ts.trimmed, "[弌壱壹]", "一") s = ustr.gsub(s, "[弍弐貮貳贰]", "二") s = ustr.gsub(s, "[弎参參叁]", "三") s = ustr.gsub(s, "肆", "四") s = ustr.gsub(s, "伍", "五") s = ustr.gsub(s, "[陸陆]", "六") s = ustr.gsub(s, "[柒漆質]", "七") s = ustr.gsub(s, "捌", "八") ts.trimmed = ustr.gsub(s, "玖", "九") s = ustr.gsub(s, "拾", "十") s = ustr.gsub(s, "廿", "二十") s = ustr.gsub(s, "念", "三十") ts.trimmed = ustr.gsub(s, "[陌佰]", "百") ts.trimmed = ustr.gsub(s, "[阡仟]", "千") s = ustr.gsub(s, "萬", "万") ts.char = mw.text.split(ts.trimmed, "") ts.next = "日時元号漢字命数" else local s = ustr.gsub(ts.trimmed, "零", "〇") s = ustr.gsub(s, "[弌壱壹]", "一") s = ustr.gsub(s, "[弍弐貮貳贰]", "二") s = ustr.gsub(s, "[弎参參叁]", "三") s = ustr.gsub(s, "肆", "四") s = ustr.gsub(s, "伍", "五") s = ustr.gsub(s, "[陸陆]", "六") s = ustr.gsub(s, "[柒漆質]", "七") s = ustr.gsub(s, "捌", "八") ts.trimmed = ustr.gsub(s, "玖", "九") ts.char = mw.text.split(ts.trimmed, "") ts.next = "日時元号漢字位取り" end
end
local state = {
{ "number|year", { call = "年", "open", "number", "close", }, "年", { call = "年", "open", "number", "年", "close", }, }, { "number|month", "月", }, { "number|day", "日", { call = "曜日", "曜日", }, }, { { call = "午", "午", }, "number|hour", "時", { call = "分秒", }, },
}
t["日時元号数字"] = function (ts)
local str = ts.char local point = ts.position - 1
function scan() local val = "" local type = "" if ts.length <= point then return "end", nil end while point < ts.length and type do point = point + 1 type = tokenpunc[str[point]] end if point + 2 <= ts.length then val = str[point] .. str[point+1] .. str[point+2] type = token3[val] if type then point = point + 2 return type, val end end if point + 1 <= ts.length then val = str[point] .. str[point+1] type = token2[val] if type then point = point + 1 return type, val end end if point <= ts.length then val = str[point] type = token1[val] if type then return type, val end end type = tokennumber[str[point]] if type == nil then return "error", nil end val = str[point] while point < ts.length do point = point + 1 type = tokennumber[str[point]] if type == nil then point = point - 1 return "number", tonumber(val) end val = val .. str[point] end return "end", nil end
local u = {}
u["年"] = function (v2) local p = point
local t, v for i3, v3 in ipairs(v2) do t, v = scan() if v3 == t then if t == "number" then if e == "明治" then if ts.year > 1872 then if ts.year + 1867 ~= v then table.insert(ts.warnings, "年不一致") return false end end elseif ts.year + era[ts.era] - 1 ~= v then table.insert(ts.warnings, "年不一致") return false end end elseif v3 == "open" then point = p return true else ts.debug = v3 .. t .. point return false end end return true end
u["曜日"] = function (v2) local p = point local t, v = scan() if t == "曜日" then ts.dayofweek = dayofweek[v] else point = p end return true end
local pm = false u["午"] = function (v2) local p = point local t, v = scan() if t == "午" then if v == "午後" then pm = true end else point = p end return true end
u["分秒"] = function (v2) local p = point local t, v = scan() if t == "number" then ts.minute = v else point = p ts.next = "timezone" if pm then ts.hour = ts.hour + 12 end ts.position = p + 1 return nil end t, v = scan() if t ~= "分" then point = p ts.next = "timezone" if pm then ts.hour = ts.hour + 12 end ts.position = p + 1 return nil end p = point t, v = scan() if t == "number" then ts.second = v else point = p ts.next = "timezone" if pm then ts.hour = ts.hour + 12 end ts.position = p + 1 return nil end t, v = scan() if t ~= "秒" then point = p ts.next = "timezone" if pm then ts.hour = ts.hour + 12 end ts.position = p + 1 return nil end return true end
if not ustr.match(ts.trimmed, "時") then table.remove(state) end
local t, v for i1, v1 in ipairs(state) do for i2, v2 in ipairs(v1) do if type(v2) == "table" then local z = u[v2.call](v2) if z == false then ts.next = nil ts.invalid = true return elseif z == nil then return end else local v21, v22 = unpack(mw.text.split(v2, "|", true)) t, v = scan() if v21 == t then if v22 then if v22 == "year" and v == 1 then ts.next = nil ts.invalid = true table.insert(ts.warning, "元号1年") end ts[v22] = v end elseif v2 == "number|year" and t == "元" then ts.year = 1 elseif t == "end" and v21 == "number" then ts.next = nil if pm then ts.hour = ts.hour + 12 end return else ts.next = nil ts.invalid = true ts.debug = v2 .. t .. point .. tostring(v) .. v21 return end end end end
if ustr.match(ts.trimmed, "時") then if pm then ts.hour = ts.hour + 12 end ts.next = "timezone" ts.position = point + 1 else ts.next = "time" ts.position = point + 1 + ustr.len(ustr.match(usub(ts.trimmed, point + 1), "^[\t\n\f\r ,-.]*")) end
end
t["日時元号漢字位取り"] = function (ts)
local tokennumber = { ["〇"] = "number", ["一"] = "number", ["二"] = "number", ["三"] = "number", ["四"] = "number", ["五"] = "number", ["六"] = "number", ["七"] = "number", ["八"] = "number", ["九"] = "number", } local n = { ["〇"] = "0", ["一"] = "1", ["二"] = "2", ["三"] = "3", ["四"] = "4", ["五"] = "5", ["六"] = "6", ["七"] = "7", ["八"] = "8", ["九"] = "9", } local str = ts.char local point = ts.position - 1
function scan() local val = "" local type = "" if ts.length <= point then return "end", nil end while point < ts.length and type do point = point + 1 type = tokenpunc[str[point]] end if point + 2 <= ts.length then val = str[point] .. str[point+1] .. str[point+2] type = token3[val] if type then point = point + 2 return type, val end end if point + 1 <= ts.length then val = str[point] .. str[point+1] type = token2[val] if type then point = point + 1 return type, val end end if point <= ts.length then val = str[point] type = token1[val] if type then return type, val end end type = tokennumber[str[point]] if type == nil then return "error", nil end val = n[str[point]] while point < ts.length do point = point + 1 type = tokennumber[str[point]] if type == nil then point = point - 1 return "number", tonumber(val) end val = val .. n[str[point]] end return "end", nil end
local u = {}
u["年"] = function (v2) local p = point
local t, v for i3, v3 in ipairs(v2) do t, v = scan() if v3 == t then if t == "number" then if e == "明治" then if ts.year > 1872 then if ts.year + 1867 ~= v then table.insert(ts.warnings, "年不一致") return false end end elseif ts.year + era[ts.era] - 1 ~= v then table.insert(ts.warnings, "年不一致") return false end end elseif v3 == "open" then point = p return true else ts.debug = v3 .. t .. point return false end end return true end
u["曜日"] = function (v2) local p = point local t, v = scan() if t == "曜日" then ts.dayofweek = dayofweek[v] else point = p end return true end
local pm = false u["午"] = function (v2) local p = point local t, v = scan() if t == "午" then if v == "午後" then pm = true end else point = p end return true end
u["分秒"] = function (v2) local p = point local t, v = scan() if t == "number" then ts.minute = v else point = p ts.next = nil--"timezone" if pm then ts.hour = ts.hour + 12 end ts.position = p + 1 return nil end t, v = scan() if t ~= "分" then point = p ts.next = nil--"timezone" if pm then ts.hour = ts.hour + 12 end ts.position = p + 1 return nil end p = point t, v = scan() if t == "number" then ts.second = v else point = p ts.next = nil--"timezone" if pm then ts.hour = ts.hour + 12 end ts.position = p + 1 return nil end t, v = scan() if t ~= "秒" then point = p ts.next = nil--"timezone" if pm then ts.hour = ts.hour + 12 end ts.position = p + 1 return nil end return true end
if not ustr.match(ts.trimmed, "時") then table.remove(state) end
local t, v for i1, v1 in ipairs(state) do for i2, v2 in ipairs(v1) do if type(v2) == "table" then local z = u[v2.call](v2) if z == false then ts.next = nil ts.invalid = true return elseif z == nil then return end else local v21, v22 = unpack(mw.text.split(v2, "|", true)) t, v = scan() if v21 == t then if v22 then if v22 == "year" and v == 1 then ts.next = nil ts.invalid = true table.insert(ts.warning, "元号1年") end ts[v22] = v end elseif v2 == "number|year" and t == "元" then ts.year = 1 elseif t == "end" and v21 == "number" then ts.next = nil if pm then ts.hour = ts.hour + 12 end return else ts.next = nil ts.invalid = true ts.debug = v2 .. t .. point .. tostring(v) .. v21 return end end end end
if ustr.match(ts.trimmed, "時") and pm then ts.hour = ts.hour + 12 end ts.next = nil
end
t["日時元号漢字命数"] = function (ts)
local tokennumber = { ["一"] = "number", ["二"] = "number", ["三"] = "number", ["四"] = "number", ["五"] = "number", ["六"] = "number", ["七"] = "number", ["八"] = "number", ["九"] = "number", ["十"] = "数詞", ["百"] = "数詞", ["千"] = "数詞", ["万"] = "数詞", } local n = { ["一"] = "1", ["二"] = "2", ["三"] = "3", ["四"] = "4", ["五"] = "5", ["六"] = "6", ["七"] = "7", ["八"] = "8", ["九"] = "9", ["十"] = 10, ["百"] = 100, ["千"] = 1000, } local str = ts.char local point = ts.position - 1
function scan() local val = "" local type = "" if ts.length <= point then return "end", nil end while point < ts.length and type do point = point + 1 type = tokenpunc[str[point]] end if point + 2 <= ts.length then val = str[point] .. str[point+1] .. str[point+2] type = token3[val] if type then point = point + 2 return type, val end end if point + 1 <= ts.length then val = str[point] .. str[point+1] type = token2[val] if type then point = point + 1 return type, val end end if point <= ts.length then val = str[point] type = token1[val] if type then return type, val end end local a = nil local b = 0 local c = 0 local d = 0 type = tokennumber[str[point]] if type == "number" then a = n[str[point]] elseif type == nil or str[point] == "万" then return "error", nil else b = n[str[point]] end while point < ts.length do point = point + 1 type = tokennumber[str[point]] if type == nil then point = point - 1 if a then b = b + a end return "number", c * 10000 + b elseif type == "number" then if a then return "error", nil else a = n[str[point]] end elseif str[point] == "万" then if c == 0 and b ~= 0 then if a then b = b + a a = nil end c = b b = 0 else return "error", nil end else if a then b = b + a * n[str[point]] a = nil else b = b + n[str[point]] end end end return "end", nil end
local u = {}
u["年"] = function (v2) local p = point
local t, v for i3, v3 in ipairs(v2) do t, v = scan() if v3 == t then if t == "number" then if e == "明治" then if ts.year > 1872 then if ts.year + 1867 ~= v then table.insert(ts.warnings, "年不一致") return false end end elseif ts.year + era[ts.era] - 1 ~= v then table.insert(ts.warnings, "年不一致") return false end end elseif v3 == "open" then point = p return true else ts.debug = v3 .. t .. point return false end end return true end
u["曜日"] = function (v2) local p = point local t, v = scan() if t == "曜日" then ts.dayofweek = dayofweek[v] else point = p end return true end
local pm = false u["午"] = function (v2) local p = point local t, v = scan() if t == "午" then if v == "午後" then pm = true end else point = p end return true end
u["分秒"] = function (v2) local p = point local t, v = scan() if t == "number" then ts.minute = v else point = p ts.next = nil--"timezone" if pm then ts.hour = ts.hour + 12 end ts.position = p + 1 return nil end t, v = scan() if t ~= "分" then point = p ts.next = nil--"timezone" if pm then ts.hour = ts.hour + 12 end ts.position = p + 1 return nil end p = point t, v = scan() if t == "number" then ts.second = v else point = p ts.next = nil--"timezone" if pm then ts.hour = ts.hour + 12 end ts.position = p + 1 return nil end t, v = scan() if t ~= "秒" then point = p ts.next = nil--"timezone" if pm then ts.hour = ts.hour + 12 end ts.position = p + 1 return nil end return true end
if not ustr.match(ts.trimmed, "時") then table.remove(state) end
local t, v for i1, v1 in ipairs(state) do for i2, v2 in ipairs(v1) do if type(v2) == "table" then local z = u[v2.call](v2) if z == false then ts.next = nil ts.invalid = true return elseif z == nil then return end else local v21, v22 = unpack(mw.text.split(v2, "|", true)) t, v = scan() if v21 == t then if v22 then if v22 == "year" and v == 1 then ts.next = nil ts.invalid = true table.insert(ts.warning, "元号1年") end ts[v22] = v end elseif v2 == "number|year" and t == "元" then ts.year = 1 elseif t == "end" and v21 == "number" then ts.next = nil if pm then ts.hour = ts.hour + 12 end return else ts.next = nil ts.invalid = true ts.debug = v2 .. t .. point .. tostring(v) .. v21 return end end end end
if ustr.match(ts.trimmed, "時") and pm then ts.hour = ts.hour + 12 end ts.next = nil
end
-- ]ja]
function v.validate(ts)
if ts.year and ts.year > 1900 then if ts.month then if ts.month == 1 or (3 <= ts.month and ts.month <= 12) then if ts.day and (ts.day < 1 or d[ts.month] < ts.day) then table.insert(ts.warnings, "範囲外/day") end elseif ts.month == 2 then if ts.day then if ts.year % 4 == 0 and (ts.year % 100 ~= 0 or ts.year % 400 == 0) then if ts.day < 1 or 29 < ts.day then table.insert(ts.warnings, "範囲外/day") end else if ts.day < 1 or 28 < ts.day then table.insert(ts.warnings, "範囲外/day") end end end else table.insert(ts.warnings, "範囲外/month") end elseif ts.dayofyear then if ts.year % 4 == 0 and (ts.year % 100 ~= 0 or ts.year % 400 == 0) then if ts.dayofyear < 1 or 366 < ts.dayofyear then table.insert(ts.warnings, "範囲外/dayofyear") end else if ts.dayofyear < 1 or 365 < ts.dayofyear then table.insert(ts.warnings, "範囲外/dayofyear") end end end end if ts.dayofweek and (ts.dayofweek < 1 or 7 < ts.dayofweek) then table.insert(ts.warnings, "範囲外/dayofweek") end if ts.hour and (ts.hour < 0 or 23 < ts.hour) then table.insert(ts.warnings, "範囲外/hour") end if ts.minute and (ts.minute < 0 or 59 < ts.minute) then table.insert(ts.warnings, "範囲外/minute") end if ts.second and (ts.second < 0 or 60 < ts.second) then table.insert(ts.warnings, "範囲外/second") end
end
function f.pf(ts, format)
local lang = mw.language.getContentLanguage()
if ts.unixtime then return lang:formatDate(format, ts.trimmed) end
if ts.hour == nil then ts.hour = 0 end if ts.minute == nil then ts.minute = 0 end if ts.second == nil then ts.second = 0 end
local date = "" if ts.dayofyear then date = string.format("%04u%03uT%02u%02u%02u", ts.year, ts.dayofyear, ts.hour, ts.minute, ts.second) elseif ts.week then if ts.dayofweek == nil then ts.dayofweek = 1 end date = string.format("%04uW%02u%1uT%02u%02u%02u", ts.yearofweek, ts.week, ts.dayofweek, ts.hour, ts.minute, ts.second) else if ts.era then ts.year = ts.year + era[ts.era] - 1 end if ts.month == nil then ts.month = 1 end if ts.day == nil then ts.day = 1 end date = string.format("%04u%02u%02uT%02u%02u%02u", ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second) end
local issuccess, ret = pcall(lang.formatDate, lang, format, date) return ret
end
function f.test(ts)
if ts.unixtime then return ts.trimmed end
if ts.hour == nil then ts.hour = 0 end if ts.minute == nil then ts.minute = 0 end if ts.second == nil then ts.second = 0 end
if ts.dayofyear then return string.format("%04u%03uT%02u%02u%02u", ts.year, ts.dayofyear, ts.hour, ts.minute, ts.second) elseif ts.week then if ts.dayofweek == nil then ts.dayofweek = 1 end return string.format("%04uW%02u%1uT%02u%02u%02u", ts.yearofweek, ts.week, ts.dayofweek, ts.hour, ts.minute, ts.second) end
if ts.era then ts.year = ts.year + era[ts.era] - 1 end if ts.month == nil then ts.month = 1 end if ts.day == nil then ts.day = 1 end return string.format("%04u%02u%02uT%02u%02u%02u", ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second)
end
return p