模組:沙盒/PexEric/1
外观
local p = {}
-- 引入模块
local argsModule = require('Module:Arguments')
local tparamValue -- 延迟加载: require('Module:Template parameter value')
-- WikiProject banner shell 及其重定向的正则表达式列表
local WIKI_PROJECT_BANNER_SHELL_REDIRECTS = {
"wiki%s*project%s*banner%s*shell",
"w?pj?%s*banner%s*shell",
"wiki%s*project%s*banners",
"multiple%s*wikiprojects?",
"wiki%s*project%s*shell",
"pjbs",
"[維维]基[专專][题題][橫横]幅",
"多?[個个]?[維维]?基?[专專][题題][橫横]幅",
"[維维]基[专專][题題]",
"多?[個个]?[維维]?基?[专專][题題]",
"[专專][题題][橫横]幅",
"通用[評评][級级]",
}
---
-- 内部函数:从指定页面获取候选项目标题
-- @param cfg table 配置表,包含: title(页面标题), pattern(提取正则), black(黑名单), blackregex(黑名单正则)
-- @return table 候选项目标题数组
local function getCandidatesFromPage(cfg)
local pageTitleObj = mw.title.new(cfg.title)
if not pageTitleObj or not pageTitleObj.exists then
mw.log("Module:CandidateProjectInfo - getCandidatesFromPage: 评选页面 '" .. cfg.title .. "' 未找到或无效。")
return {}
end
local pageContent = pageTitleObj:getContent()
if not pageContent then
mw.log("Module:CandidateProjectInfo - getCandidatesFromPage: 评选页面 '" .. cfg.title .. "' 内容为空。")
return {}
end
local matches = {}
local blackList = {}
if cfg.black and cfg.black ~= '' then
for b in mw.text.gsplit(cfg.black, '|', true) do
blackList[mw.text.trim(b)] = true
end
end
for m in mw.ustring.gmatch(pageContent, cfg.pattern) do
m = mw.text.trim(m)
if m ~= '' and not blackList[m] and not (cfg.blackregex and cfg.blackregex ~= '' and mw.ustring.match(m, cfg.blackregex)) then
table.insert(matches, m)
end
end
if #matches == 0 then
mw.log("Module:CandidateProjectInfo - getCandidatesFromPage: 在页面 '" .. cfg.title .. "' 使用模式 '" .. cfg.pattern .. "' 未找到候选项目。")
end
return matches
end
---
-- 内部函数:从讨论页获取维基专题名称
-- @param talkPageFullName string 讨论页完整标题
-- @return table 专题模板名称数组
local function getProjectsFromTalkPage(talkPageFullName)
if not tparamValue then -- 延迟加载
tparamValue = require('Module:Template parameter value')
end
mw.log("Module:CandidateProjectInfo - getProjectsFromTalkPage: 尝试为讨论页 '" .. talkPageFullName .. "' 获取专题。")
local success, bannerContentOrError = tparamValue.getParameter(
talkPageFullName,
WIKI_PROJECT_BANNER_SHELL_REDIRECTS,
'1', -- {{WikiProject banner shell}} 的第一个匿名参数
{
treat_as_regex = true, -- WIKI_PROJECT_BANNER_SHELL_REDIRECTS 使用正则
template_index = 1, -- 获取第一个匹配的 banner shell
-- ignore_blank = true -- 如果参数1为空,TPV应该返回空字符串而不是错误
}
)
if not success then
mw.log("Module:CandidateProjectInfo - getProjectsFromTalkPage: 调用 tparamValue.getParameter 失败,讨论页 '" .. talkPageFullName .. "'。错误: " .. tostring(bannerContentOrError))
return {}
end
if not bannerContentOrError or bannerContentOrError:match("^%s*$") then
mw.log("Module:CandidateProjectInfo - getProjectsFromTalkPage: WikiProject banner shell 参数1为空或未找到,讨论页 '" .. talkPageFullName .. "'。获取到的内容: " .. tostring(bannerContentOrError))
return {}
end
mw.log("Module:CandidateProjectInfo - getProjectsFromTalkPage: 成功获取banner shell参数1内容,讨论页 '" .. talkPageFullName .. "'。内容片段: " .. mw.text.truncate(bannerContentOrError, 100, "..."))
local projects = {}
-- 从 banner shell 的参数1内容中提取模板名
-- 正则含义: {{可选空格 捕获(非}|的字符) 可选空格 可选|...}}
for name_part in mw.ustring.gmatch(bannerContentOrError, "{{%s*([^}|]+)") do
local projectName = mw.text.trim(name_part)
if projectName ~= "" and not projectName:match("^[Tt]alkheader") and not projectName:match("^[Pp]age assessments") then -- 过滤一些常见非专题模板
local found = false -- 避免重复添加同一专题
for _, existing_proj in ipairs(projects) do
if existing_proj == projectName then
found = true
break
end
end
if not found then
table.insert(projects, projectName)
mw.log("Module:CandidateProjectInfo - getProjectsFromTalkPage: 讨论页 '" .. talkPageFullName .. "' 找到专题: " .. projectName)
end
end
end
if #projects == 0 then
mw.log("Module:CandidateProjectInfo - getProjectsFromTalkPage: 讨论页 '" .. talkPageFullName .. "' 的banner shell参数1内容中未解析出专题。原始内容片段: " .. mw.text.truncate(bannerContentOrError, 100, "..."))
end
return projects
end
---
-- 内部函数:格式化条目项(链接 + 前后缀应用于原始标题文本)
-- @param article_title_raw string 从评选页提取的原始条目标题
-- @param linkprefix_val string|nil 链接目标前缀
-- @param item_prefix_val string 条目项前缀
-- @param item_suffix_val string 条目项后缀
-- @return string 格式化后的条目项wikitext链接
local function formatArticleItem(article_title_raw, linkprefix_val, item_prefix_val, item_suffix_val)
-- item_prefix 和 item_suffix 直接包裹原始纯文本标题
local display_text_for_pipe = item_prefix_val .. article_title_raw .. item_suffix_val
local core_link
local link_target = article_title_raw -- 链接目标是原始标题
if linkprefix_val and linkprefix_val ~= "" then
core_link = string.format('[[:%s%s|%s]]', linkprefix_val, link_target, display_text_for_pipe)
else
core_link = string.format('[[:%s|%s]]', link_target, display_text_for_pipe)
end
return core_link
end
---
-- 函数1: 以表格形式列出候选项目及其所属专题
-- @param frame table Scribunto frame 对象
function p.listProjectsForCandidates(frame)
local args = argsModule.getArgs(frame, {removeBlanks = false})
local review_page_title = args.title
local candidate_pattern = args.pattern
if not review_page_title or review_page_title == '' or not candidate_pattern or candidate_pattern == '' then
return '<span class="error">错误:参数 "title" 和 "pattern" 不能为空。</span>'
end
local candidate_cfg = {
title = review_page_title,
pattern = candidate_pattern,
black = args.black,
blackregex = args.blackregex
}
local candidates = getCandidatesFromPage(candidate_cfg)
if #candidates == 0 then
return args.ifnone or "暂无候选项目"
end
local item_prefix = args.item_prefix or ""
local item_suffix = args.item_suffix or ""
local tpl_prefix = args.tpl_prefix or "{{tl|"
local tpl_suffix = args.tpl_suffix or "}}"
local linkprefix = args.linkprefix
local output_table = {}
table.insert(output_table, '{| class="wikitable sortable"')
table.insert(output_table, '! 条目 !! 所属专题')
for _, article_title_raw in ipairs(candidates) do
local projects_string = args.projectifnone or "<em>未找到所属专题信息</em>" -- 默认值
local formatted_article = formatArticleItem(article_title_raw, linkprefix, item_prefix, item_suffix) -- 提前格式化条目链接
if type(article_title_raw) == "string" and article_title_raw ~= "" then
local mainArticleTitleObj = mw.title.new(article_title_raw)
if mainArticleTitleObj then
local talkPageTitleObj = mainArticleTitleObj:getTalkPage()
if talkPageTitleObj then
-- 确保讨论页实际存在才去获取内容和专题
if talkPageTitleObj.exists then
local projects = getProjectsFromTalkPage(talkPageTitleObj:getFullText())
if #projects > 0 then
local projects_formatted_list = {}
for _, proj_name in ipairs(projects) do
table.insert(projects_formatted_list, tpl_prefix .. proj_name .. tpl_suffix)
end
projects_string = table.concat(projects_formatted_list, "、")
else
-- getProjectsFromTalkPage 内部会log,这里可以用默认的 "未找到"
end
else
mw.log("Module:CandidateProjectInfo - listProjectsForCandidates: 讨论页 '" .. talkPageTitleObj:getFullText() .. "' (来自条目 '".. article_title_raw .."') 不存在。")
projects_string = args.projectifnone or "<em>讨论页不存在</em>"
end
else
mw.log("Module:CandidateProjectInfo - listProjectsForCandidates: 无法获取条目 '" .. article_title_raw .. "' 的讨论页对象。")
projects_string = args.projectifnone or "<em>无讨论页对象</em>"
end
else
mw.log("Module:CandidateProjectInfo - listProjectsForCandidates: 无法为 '" .. article_title_raw .. "' 创建主条目title对象。")
projects_string = "<em>无效条目名</em>"
end
else
mw.log("Module:CandidateProjectInfo - listProjectsForCandidates: 候选列表中发现无效条目名: " .. tostring(article_title_raw))
projects_string = "<em>无效条目名</em>"
formatted_article = item_prefix .. tostring(article_title_raw) .. item_suffix -- 尽力显示
end
table.insert(output_table, '|-')
table.insert(output_table, '| ' .. formatted_article .. '\n| ' .. projects_string)
end
table.insert(output_table, '|}')
return table.concat(output_table, '\n')
end
---
-- 函数2: 按指定专题筛选候选项目
-- @param frame table Scribunto frame 对象
function p.filterCandidatesByProjects(frame)
local args = argsModule.getArgs(frame, {removeBlanks = false})
local review_page_title = args.title
local candidate_pattern = args.pattern
if not review_page_title or review_page_title == '' or not candidate_pattern or candidate_pattern == '' then
return '<span class="error">错误:参数 "title" 和 "pattern" 不能为空。</span>'
end
local project_regexes = {}
for k, v in pairs(args) do
if type(k) == 'string' and k:match("^project%d+$") and v and v ~= '' then
table.insert(project_regexes, v)
end
end
if #project_regexes == 0 then
return '<span class="error">错误:必须提供至少一个 "projectN" 参数用于筛选。</span>'
end
local candidate_cfg = {
title = review_page_title,
pattern = candidate_pattern,
black = args.black,
blackregex = args.blackregex
}
local candidates = getCandidatesFromPage(candidate_cfg)
if #candidates == 0 then
return args.ifnone or "暂无候选项目"
end
local item_prefix = args.item_prefix or ""
local item_suffix = args.item_suffix or ""
local linkprefix = args.linkprefix
local matching_articles_formatted = {}
for _, article_title_raw in ipairs(candidates) do
if type(article_title_raw) == "string" and article_title_raw ~= "" then
local mainArticleTitleObj = mw.title.new(article_title_raw)
if mainArticleTitleObj then
local talkPageTitleObj = mainArticleTitleObj:getTalkPage()
if talkPageTitleObj and talkPageTitleObj.exists then
local article_projects = getProjectsFromTalkPage(talkPageTitleObj:getFullText())
if #article_projects > 0 then
local matched_project = false
for _, actual_proj_name in ipairs(article_projects) do
for _, proj_regex in ipairs(project_regexes) do
local regex_match_success, _ = pcall(mw.ustring.match, actual_proj_name, proj_regex)
if regex_match_success and mw.ustring.match(actual_proj_name, proj_regex) then
matched_project = true
break
end
end
if matched_project then break end
end
if matched_project then
local formatted_article = formatArticleItem(article_title_raw, linkprefix, item_prefix, item_suffix)
table.insert(matching_articles_formatted, formatted_article)
end
end
else
if talkPageTitleObj then
mw.log("Module:CandidateProjectInfo - filterCandidatesByProjects: 讨论页 '" .. talkPageTitleObj:getFullText() .. "' (来自条目 '".. article_title_raw .."') 不存在。")
else
mw.log("Module:CandidateProjectInfo - filterCandidatesByProjects: 无法获取条目 '" .. article_title_raw .. "' 的讨论页对象。")
end
end
else
mw.log("Module:CandidateProjectInfo - filterCandidatesByProjects: 无法为 '" .. article_title_raw .. "' 创建主条目title对象。")
end
else
mw.log("Module:CandidateProjectInfo - filterCandidatesByProjects: 候选列表中发现无效条目名: " .. tostring(article_title_raw))
end
end
if #matching_articles_formatted == 0 then
return args.projectifnone or "没有找到符合指定专题条件的候选项目。"
end
return '# ' .. table.concat(matching_articles_formatted, '\n# ')
end
return p