2023年政策修订增补工作正在进行中,欢迎参与!
Module:少女歌剧
跳转到导航
跳转到搜索
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