local module = {}
module.BASEPAGE = "Module:少女歌劇" -- 常量,表示獲取少女歌劇專題信息查詢模塊根頁面路徑。
module.DATABASEPAGE = module.BASEPAGE .. "/Data" -- 常量,表示獲取Data的模塊根頁面路徑。
module.NGROUPPAGE = module.BASEPAGE .. "/NGroup" -- 常量,表示獲取名稱組列表的模塊根頁面路徑。
local mps = require("Module:ModulePageSystem")
--[==[
加載某一個模塊頁中的數據。
--]==]
local loadData = function(page, ignoreerror)
if page == nil then return nil end
local title = mw.title.new(page)
if title == nil then
mps.util.error(mw.ustring.format("加載數據頁\"%s\"時發生錯誤:%s", page, "頁面路徑地址不符合規範。"), mps.util.ELID_WARNING)
return nil
elseif not title.exists then
mps.util.error(mw.ustring.format("加載數據頁\"%s\"時發生錯誤:%s", page, "頁面不存在。"), mps.util.ELID_WARNING)
return nil
end
local success, result = pcall(mw.loadData, page)
if success then
return result
else
mps.util.error(mw.ustring.format("加載數據頁\"%s\"時發生錯誤:%s", page, result), mps.util.ELID_WARNING)
return nil
end
end
--[==[
獲取傳入的參數,若#invoke時傳入至少一個以數字為參數名的參數,則使用#invoke時傳入的參數列表;否則使用包裝了模塊#invoke的模板傳入的參數列表。
--]==]
local getArgs = function(frame)
local args
if (function()
for k, _ in pairs(frame.args) do
if type(k) == "number" then
return true
end
end
end)() then
args = frame.args
else
args = require("Module:Arguments").getArgs(frame:getParent() or frame)
end
return args
end
--[==[
獲取分級索引關鍵詞。
--]==]
local getPath = function(args, normalize)
local path = {}
for _, name in ipairs(args) do
if normalize == true then name = mps.util.normalize(name) end
table.insert(path, name)
end
return path
end
-- 可匹配多個正則。
mw.ustring.gsub_m = function(s, patterns, repl, n)
local length = mw.ustring.len(s)
local init = 1
local v1, v2
local i = 0
local ss = {}
while (n == nil or i < n) and init < length do
v1, v2 = length + 1, length
local p = nil
for _, pattern in ipairs(patterns) do
local v3, v4 = mw.ustring.find(s, pattern, init, false)
if v3 ~= nil and (v3 < v1 or (v3 == v1 and v4 <= v2)) then
v1, v2 = v3, v4 -- 更新匹配範圍。
p = pattern -- 更新使用的正則。
end
end
if p ~= nil then
table.insert(ss, mw.ustring.sub(s, init, v1 - 1))
local new_s = mw.ustring.gsub(mw.ustring.sub(s, v1, v2), p, repl, 1) -- 調用原生替換函數。
table.insert(ss, new_s)
else break
end
init = v2 + 1
i = i + 1
end
table.insert(ss, mw.ustring.sub(s, init))
return table.concat(ss)
end
module.gsub_m = function(str, func)
local patterns = {
"(%$(%$))",
"(%$%(([^)]*)%))",
"(%$(%d))",
"(%$([^($]))"
}
return mw.ustring.gsub_m(str, patterns, func or "-")
end
function module.data(frame)
local args = getArgs(frame)
local ignoreerror = frame.args.ignoreerror == "yes" or args.ignoreerror == "yes" or false
local path = getPath(args)
local page = frame.args.page or args.page or module.DATABASEPAGE
local params = { ngpage = { path = module.NGROUPPAGE, data = loadData(module.NGROUPPAGE) or {} } }
local result = loadData(page, true) or {}
for index, name in ipairs(path) do
if type(result) ~= "table" then -- 上級節點含有值。
-- 回溯一次查詢,並將上級節點的鍵作為目錄嘗試加載本級頁面,以重新從本級頁面中查詢。
page = mw.ustring.format("%s/%s", page, path[index - 1])
result = loadData(page, true) or {}
end
local keyexists = false
for cname, subnodes in pairs(result) do
if mps.util.KEYCOMPARER_NGROUP(cname, name, params) then -- 表中含有這個值
result = subnodes
keyexists = true
end
end
if not keyexists then
-- 嘗試加載次級頁面,以從次級頁面中繼續查詢。
page = mw.ustring.format("%s/%s", page, name)
result = loadData(page, true) or {}
end
end
if type(result) == "table" then -- 查詢結果不是值。
if not ignoreerror then error("查詢到的值為空(可能在指定名稱上的值的類型不是字符串,或者指定名稱不存在)。")
else return nil
end
else
-- 成功查詢到值。
return result
end
end
--[==[
【將要棄用】
--]==]
local vardefine = function(name, value, frame)
local wiki
if mw.ustring.sub(value, 1, 1) == "$" then -- 是wiki
wiki = mw.ustring.gsub(mw.ustring.sub(value, 2), "%%[%%$]", function(m)
if m == "%%" then return "%"
elseif m == "%$" then return "$"
else return ""
end
end)
wiki = frame:preprocess(wiki)
else
wiki = value
end
return frame:callParserFunction("#vardefine", name, wiki)
end
--[==[
將指定的名稱組通過{{#vardefine}}寫入到維基文本中。
--]==]
function module.ngroup(frame)
local ngroup = mw.loadData(module.NGROUPPAGE)
local vdexprs = {}
for gname, names in pairs(ngroup) do
if type(gname) == "string" then
for _, name in ipairs(names) do
local expr = vardefine(mw.ustring.format("%s %s", "名稱組", name), gname, frame)
if expr ~= nil then
table.insert(vdexprs, expr) -- 添加定義語句。
end
end
end
end
return table.concat(vdexprs)
end
--[==[
將指定的數據通過{{#vardefine}}寫入到維基文本中。
--]==]
function module.define(frame)
local args = getArgs(frame)
local datapage
if mw.ustring.match(args.datapage or "", "^[/\\]") then -- 是相對路徑
datapage = module.DATABASEPAGE .. args.datapage
else -- 是絕對路徑
datapage = args.datapage
end
local ngroup = mw.loadData(module.NGROUPPAGE)
local vdexprs = {}
local function defineInternal(data, path, dir)
if type(data) == "table" then
if #path == 0 then table.insert(path, "$") end -- 若path提供的匹配列表沒有查詢到底層節點,則插入默認的匹配所有鍵正則以查詢到底層節點。
elseif type(data) == "string" then
if #path > 0 then error("無法繼續向下層節點查詢,因為當前節點已經是底層節點。") end
local expr = vardefine(dir, data, frame)
if expr ~= nil then
table.insert(vdexprs, expr) -- 添加定義語句。
end
return
else return -- 不支持其他類型的值。
end
local pattern = path[1]
local isngroup = mw.ustring.sub(pattern, 1, 2) == "$$" -- 僅匹配名稱組時在開頭添加兩個$字符。
local isall = not isngroup and (mw.ustring.sub(pattern, 1, 1) == "$") -- 匹配所有鍵時在開頭添加一個$字符。
for dkey, dvalue in pairs(data) do
if isall or (mw.ustring.sub(dkey, 1, 1) == "$") == isngroup then -- 同或,表示數據鍵和查找鍵正則同時是或同時不是名稱組。
if mw.ustring.sub(dkey, 1, 1) == "$" then -- 數據鍵是名稱組。
local ngkey = mps.util.normalize(mw.ustring.sub(dkey, 2)) -- 獲取名稱組鍵。
if isall then
pattern = mw.ustring.sub(pattern, 2) -- 獲取正則。
elseif isngroup then
pattern = mw.ustring.sub(pattern, 3) -- 獲取正則。
end
if mw.ustring.match(ngkey, pattern) then -- 匹配成功。
local newdata = dvalue
local newpath = {}
for i = 2, #path do table.insert(newpath, path[i]) end
local newdir
if dir == nil then
newdir = ngkey
else
newdir = mw.ustring.format("%s %s", dir, ngkey)
end
defineInternal(newdata, newpath, newdir)
end
else -- 數據鍵不是名稱組。
dkey = mps.util.normalize(dkey)
if isall then
pattern = mw.ustring.sub(pattern, 2) -- 獲取正則。
end
if mw.ustring.match(dkey, pattern) then -- 匹配成功。
local newdata = dvalue
local newpath = {}
for i = 2, #path do table.insert(newpath, path[i]) end
local newdir
if dir == nil then
newdir = dkey
else
newdir = mw.ustring.format("%s %s", dir, dkey)
end
defineInternal(newdata, newpath, newdir)
end
end
end
end
end
defineInternal(mw.loadData(datapage), getPath(args), nil)
return table.concat(vdexprs)
end
-- Only for Template:九九組成員對她的稱呼 and Template:舞台少女稱呼表
function module.aishou(frame)
local args = frame.args
local data = mw.loadData(module.DATABASEPAGE.."/角色稱呼表")
local name = args.name or "愛城華戀" -- 她的名字。
local node = mw.html.create("table")
:css("font-size", "89%")
:css("text-align", "center")
:css("max-width", "260px")
:css("float", "right")
:css("background-color", "white")
:tag("tr"):tag("th")
:css("color", "white")
:css("background-color", frame:callParserFunction{ name = "#var", args = { name } })
:css("font-size", "100%")
:css("font-weight", "bold")
:css("padding", "1em")
:attr("colspan", 2)
:wikitext("其他人對")
:wikitext(frame:expandTemplate{ title = "少女歌劇/角色信息", args = { name, "姓名地區轉換" } })
:wikitext("的稱呼")
:allDone()
for _, cname in ipairs(module.sortNameGroup()) do
local cothers = data["$" .. cname] or {}
for cother, ass in pairs(cothers) do
cother = mw.text.trim(cother, "$") -- 簡單處理。
if name == cother then
-- 處理格式字符串 --
local as_process = function(as)
local patterns = {
"(%$(%$))",
"(%$%(([^)]*)%))",
"(%$([^($]))"
}
-- 進行通用格式字符串替換,獲得新格式字符串。
as = mw.ustring.gsub_m(as, patterns, function(rawtext, matchtext)
if rawtext == "$$" then return "$$"
else
local numindex = tonumber(matchtext) -- 如果索引值是數字,優先轉換為number類型鍵。
if numindex then
return data.COMMON[numindex] or data.COMMON[matchtext] or rawtext
else
if not mw.ustring.find(matchtext, "^日文") then
matchtext = "日文"..matchtext -- 在前方添加“日文”。
rawtext = "$("..matchtext..")" -- 在前方添加“日文”。
end
return data.COMMON[matchtext] or rawtext
end
end
end)
as = mw.ustring.gsub_m(as, patterns, function(rawtext, matchtext)
if rawtext == "$$" then return "$"
else
return frame:expandTemplate{ title = "少女歌劇/角色信息", args = { name, matchtext } } -- 調用模板,獲取角色信息。
end
end)
return as
end
local empty = false
if type(ass) == "table" then
local _ass = {}
for i_as, as in ipairs(ass) do
_ass[i_as] = frame:expandTemplate{ title = "lj", args = { as_process(as) } }
end
if #_ass == 0 then empty = true
else
ass = table.concat(_ass, "、")
end
else
if mw.text.trim(ass) == "" then empty = true
else
ass = frame:expandTemplate{ title = "lj", args = { as_process(ass) } }
end
end
if not empty then
local ltext
if name == cname then
ltext = "自稱"
else
ltext =
frame:expandTemplate{ title = "少女歌劇/角色表述", args =
{
cname,
"內鏈",
frame:expandTemplate{ title = "Color", args =
{
"white",
frame:expandTemplate{ title = "少女歌劇/角色信息", args = { cname, "名地區轉換" } }
} }
} }
end
--------------------
node:tag("tr")
:tag("td")
:css("color", "white")
:css("background-color", frame:callParserFunction{ name = "#var", args = { cname } })
:css("font-weight", "bold")
:css("padding", "0 1em")
:css("min-width", "80px")
:wikitext(ltext)
:done()
:tag("td")
:css("padding", "0 1em")
:css("min-width", "140px")
:wikitext(ass)
end
end
end
end
return tostring(node)
end
-- 對名稱組列表list,按categories(匿名函數)列表指示的順序排序。
function module.sortNameGroup(list, --[[ categories ]]...)
local categories = {}
-- 整理排序分類列表。
for i = 1, select("#", ...) do
local cat = select(i, ...)
if cat then
table.insert(categories, cat)
end
end
local data = loadData(module.NGROUPPAGE) -- 加載名稱組數據。
if #categories == 0 then categories = data[0] end -- 使用默認排序分類列表。
local result = {}
for _, cat in ipairs(categories) do
for _, catinfo in ipairs(data) do
if catinfo.category == cat then
for _, _ng in ipairs(catinfo) do
if type(list) == "table" then
for _, ng in ipairs(list) do
if ng == _ng then
table.insert(result, ng)
end
end
elseif type(list) == "string" and list == _ng then
table.insert(result, list)
elseif list == nil then
table.insert(result, _ng)
else
mps.util.error(mw.ustring.format("參數list的值類型錯誤。(應為%s,實際為%s)", "table、string或nil", type(list)), mps.util.ELID_ERROR)
end
end
end
end
end
return result
end
return module