模組:沙盒/PexEric/1
外观
-- Module:CandidateProjectUtils
local p = {}
-- #############################################################################
-- # 依赖模块加载 (TplParamValue 仍然是可选的,因为其核心函数被复制了)
-- #############################################################################
-- local TplParamValue -- No longer strictly needed as matchAllTemplates is self-contained
-- #############################################################################
-- # 内部辅助函数:获取候选条目 (逻辑从 PatternedCandidateUtils 移入)
-- #############################################################################
local function internal_get_candidates(args_table)
if not args_table or not args_table.title or not args_table.pattern then
-- mw.log("CandidateProjectUtils:internal_get_candidates - Error: args_table, title, or pattern is nil.")
-- return {} -- 保持原样,因为这个函数内部已经处理了
end
-- Debugging: Log received arguments (if possible, or use preprocess for output)
-- local debug_info = {}
-- for k, v in pairs(args_table or {}) do table.insert(debug_info, k .. "=" .. tostring(v)) end
-- mw.log("internal_get_candidates received: " .. table.concat(debug_info, ", "))
local page_content
local title_obj = mw.title.new( args_table.title )
if not title_obj then
-- mw.log("CandidateProjectUtils:internal_get_candidates - Invalid title provided: " .. tostring(args_table.title))
return {}
end
page_content = title_obj:getContent()
if not page_content then
-- mw.log("CandidateProjectUtils:internal_get_candidates - No content for title: " .. tostring(args_table.title))
return {}
end
-- mw.log("internal_get_candidates - Page content length for " .. args_table.title .. ": " .. #page_content) -- For debugging
local matches = {}
local black = {}
if args_table.black then
for b in mw.text.gsplit( args_table.black, '|', true ) do
if type(b) == "string" and b ~= "" then
black[b] = true
end
end
end
if type(args_table.pattern) ~= "string" then
-- mw.log("CandidateProjectUtils:internal_get_candidates - Pattern is not a string: " .. tostring(args_table.pattern))
return {}
end
-- mw.log("internal_get_candidates - Using pattern: " .. args_table.pattern) -- For debugging
for m in mw.ustring.gmatch( page_content, args_table.pattern ) do
-- mw.log("internal_get_candidates - Matched raw: " .. m) -- For debugging
if not black[m] and not ( args_table.blackregex and type(args_table.blackregex) == "string" and mw.ustring.match( m, args_table.blackregex ) ) then
table.insert( matches, m )
-- mw.log("internal_get_candidates - Added to matches: " .. m) -- For debugging
end
end
-- mw.log("internal_get_candidates - Total matches found: " .. #matches) -- For debugging
return matches
end
-- get_raw_candidates 现在直接调用 internal_get_candidates
local function get_raw_candidates(pcu_args_table)
return internal_get_candidates(pcu_args_table)
end
-- #############################################################################
-- # 内部辅助函数:提取模板名 (改编自 Module:Template parameter value)
-- #############################################################################
local function matchAllTemplates(str)
local matches = {}
if type(str) ~= "string" then return matches end
for template in string.gmatch(str, "{%b{}}") do
table.insert(matches, template)
local innerContent = string.sub(template, 3, -3)
local sub_matches = matchAllTemplates(innerContent)
for _,subtemplate in ipairs(sub_matches) do
table.insert(matches, subtemplate)
end
end
return matches
end
-- #############################################################################
-- # 内部辅助函数:获取条目讨论页的专题列表
-- #############################################################################
local function pjbs_getTemplateSection(input_text)
local text = (input_text or '')..'\n'
local i,j = mw.ustring.find(text, "\n%=+[^\n]*%=+%s*\n")
if i == nil then
i,j = mw.ustring.find(text, "%{%{%s*[Dd][Yy][Kk][Ee]ntry/archive")
end
text = mw.ustring.sub(text, 1, (i or 0)-1)
return text
end
local function pjbs_processWPBSRedirect(input_text)
local text = input_text
if not text then return "" end
local norm_name = "WPBS"
local match_list = {
"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",
"[維维]基[专專][题題][橫横]幅", "多?[個个]?[維维]?基?[专專][题題][橫横]幅",
"[維维]基[专專][题題]", "多?[個个]?[維维]?基?[专專][题題]",
"[专專][题題][橫横]幅", "通用[評评][級级]",
}
local lotext = mw.ustring.gsub(mw.ustring.lower(text), "_", " ")
local normtext = text
for i = 1,#match_list do
local j, k = mw.ustring.find(lotext, match_list[i])
while j ~= nil do
normtext = mw.ustring.sub(normtext, 1, j-1)..norm_name..mw.ustring.sub(normtext, k+1, -1)
lotext = mw.ustring.gsub(mw.ustring.lower(normtext), "_", " ")
j, k = mw.ustring.find(lotext, match_list[i])
end
end
normtext = mw.ustring.gsub(normtext, "[Ww][Pp][Bb][Ss]", "WikiProject banner shell")
text = normtext
return text
end
local function pjbs_getWPBSTemplateContent(input_text)
if not input_text then return '' end
local text = input_text
local re_WPBS_header = "%{%{[^%{%}%|]*[Ww]iki[Pp]roject[%s_]*[Bb]anner[%s_]*[Ss]hell"
local it = text
local old_it = text.."-"
while it ~= old_it do
if not mw.ustring.match(it, re_WPBS_header) then break end
old_it = it
it = mw.ustring.gsub(it, "%{[^%{%}]*%}", "")
end
local WPBS = mw.ustring.match(old_it, re_WPBS_header.."[^%{%}]*%}%}") or ''
return WPBS
end
local function get_article_wikiprojects(article_title_str)
local projects = {}
local unique_project_names = {}
if not article_title_str or article_title_str == '' then
return {}
end
local article_title_obj = mw.title.new(article_title_str)
if not article_title_obj then
return {}
end
local talk_page_title = article_title_obj.talkPageTitle
if not talk_page_title or not talk_page_title.exists or talk_page_title.isRedirect then
return {}
end
local talk_content = talk_page_title:getContent()
if not talk_content or talk_content == '' then
return {}
end
local banner_section_text = pjbs_getTemplateSection(talk_content)
local processed_banner_section_text = pjbs_processWPBSRedirect(banner_section_text)
local wpbs_template_wikitext = pjbs_getWPBSTemplateContent(processed_banner_section_text)
local text_to_scan_for_templates
if wpbs_template_wikitext and wpbs_template_wikitext ~= "" then
text_to_scan_for_templates = mw.ustring.match(wpbs_template_wikitext, "{{[^|]+|(.*)}}") or ""
else
text_to_scan_for_templates = processed_banner_section_text
end
local all_found_templates_code = matchAllTemplates(text_to_scan_for_templates)
for _, tpl_code in ipairs(all_found_templates_code) do
local core_part = mw.ustring.sub(tpl_code, 3, -3)
local tpl_name = mw.text.trim( (mw.ustring.match(core_part, "^([^|]+)") or core_part) )
if tpl_name and #tpl_name > 0 then
-- 尝试去除模板名前可能存在的命名空间前缀,如 "Template:"
tpl_name = mw.ustring.gsub(tpl_name, "^[Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee]:", "")
tpl_name = mw.text.trim(tpl_name)
local normalized_tpl_name = mw.ustring.upper(mw.ustring.sub(tpl_name, 1, 1)) .. mw.ustring.sub(tpl_name, 2)
local lower_tpl_name = mw.ustring.lower(normalized_tpl_name)
if (mw.ustring.find(lower_tpl_name, "^wikiproject") or
mw.ustring.find(lower_tpl_name, "^wp%s") or -- "WP Foo" (note the space)
mw.ustring.find(lower_tpl_name, "^wp_") or -- "WP_Foo"
mw.ustring.find(tpl_name, "专题") or
mw.ustring.find(tpl_name, "專題")) and
lower_tpl_name ~= "wikiproject banner shell" and
lower_tpl_name ~= "wpbs" and
lower_tpl_name ~= "pjbs" and
not mw.ustring.find(lower_tpl_name, "/sandbox$") and
not mw.ustring.find(lower_tpl_name, "/doc$")
then
if not unique_project_names[lower_tpl_name] then
table.insert(projects, normalized_tpl_name)
unique_project_names[lower_tpl_name] = true
end
end
end
end
if #projects > 0 then
table.sort(projects)
end
return projects
end
-- #############################################################################
-- # 主要函数
-- #############################################################################
function p.list_candidates_with_projects(frame)
-- 获取传递给 #invoke 的参数
local args = frame.args
-- Debug: Log received arguments
-- local debug_args_list = {}
-- for k, v in pairs(args or {}) do table.insert(debug_args_list, k .. "='" .. tostring(v) .. "'") end
-- if #debug_args_list == 0 then
-- return "Error: No arguments received by list_candidates_with_projects. Args table is empty or nil."
-- else
-- -- return "Debug list_candidates_with_projects - Args: " .. table.concat(debug_args_list, "; ")
-- end
local pcu_args_table = {
title = args.pcu_title,
pattern = args.pcu_pattern,
black = args.pcu_black,
blackregex = args.pcu_blackregex
}
-- -- More specific debug for pcu_args_table just before calling get_raw_candidates
-- local pcu_debug = {}
-- for k, v in pairs(pcu_args_table) do table.insert(pcu_debug, k .. "=" .. tostring(v)) end
-- if not pcu_args_table.title or not pcu_args_table.pattern then
-- return "Error: pcu_title or pcu_pattern is missing before calling get_raw_candidates. pcu_args: " .. table.concat(pcu_debug, ", ")
-- end
-- -- return "Debug: About to call get_raw_candidates with: " .. table.concat(pcu_debug, ", ") -- Temporary return for debugging
local item_prefix = args.item_prefix or ''
local item_suffix = args.item_suffix or ''
local candidates = get_raw_candidates(pcu_args_table)
-- if candidates == nil then return "Error: get_raw_candidates returned nil." end -- Should not happen as it returns {}
-- if #candidates == 0 then -- Debug: Explicitly check after call
-- return (args.no_candidates_msg or "暂无候选项目.") .. " (Debug: Candidate list empty after get_raw_candidates)"
-- end
if #candidates == 0 then
return args.no_candidates_msg or "暂无候选项目。"
end
local output_rows = {}
table.insert(output_rows, '{| class="wikitable sortable"')
table.insert(output_rows, '! 条目名 !! 所属专题')
for i, article_name_raw in ipairs(candidates) do
local article_name_display = string.gsub(article_name_raw, "_", " ")
local projects = get_article_wikiprojects(article_name_raw)
local formatted_projects_list = {}
if #projects > 0 then
for _, proj_name in ipairs(projects) do
table.insert(formatted_projects_list, "{{tl|" .. proj_name .. "}}")
end
end
local projects_str = table.concat(formatted_projects_list, "、")
if projects_str == "" then
projects_str = args.no_projects_found_msg or "(未找到专题)"
end
local formatted_article_link = item_prefix .. article_name_display .. item_suffix
table.insert(output_rows, '|-\n| ' .. formatted_article_link .. ' \n| ' .. projects_str)
end
table.insert(output_rows, '|}')
return table.concat(output_rows, '\n')
end
function p.filter_candidates_by_projects(frame)
-- 获取传递给 #invoke 的参数
local args = frame.args
-- Debug: Log received arguments
-- local debug_args_list = {}
-- for k, v in pairs(args or {}) do table.insert(debug_args_list, k .. "='" .. tostring(v) .. "'") end
-- if #debug_args_list == 0 then
-- return "Error: No arguments received by filter_candidates_by_projects. Args table is empty or nil."
-- else
-- -- return "Debug filter_candidates_by_projects - Args: " .. table.concat(debug_args_list, "; ")
-- end
local pcu_args_table = {
title = args.pcu_title,
pattern = args.pcu_pattern,
black = args.pcu_black,
blackregex = args.pcu_blackregex
}
local item_prefix = args.item_prefix or ''
local item_suffix = args.item_suffix or ''
local target_projects_str = args.target_projects -- No 'or ""' here yet, check for nil explicitly
if target_projects_str == nil or mw.text.trim(target_projects_str) == "" then -- Check for nil and empty string after trim
return "错误:未指定目标专题 (target_projects 参数为空或未提供)。"
end
local target_projects_map = {}
for proj in mw.text.gsplit(target_projects_str, ',', true) do
local trimmed_proj = mw.text.trim(proj)
if trimmed_proj ~= "" then
target_projects_map[mw.ustring.lower(trimmed_proj)] = true
end
end
if next(target_projects_map) == nil then
return "错误:目标专题列表处理后为空 (target_projects 参数可能只包含逗号、空格或无效字符)。"
end
local candidates = get_raw_candidates(pcu_args_table)
if #candidates == 0 then
return args.no_candidates_msg or "暂无候选项目。"
end
local output_items = {}
for i, article_name_raw in ipairs(candidates) do
local article_name_display = string.gsub(article_name_raw, "_", " ")
local article_projects = get_article_wikiprojects(article_name_raw)
local match_found = false
for _, found_proj_name in ipairs(article_projects) do
if target_projects_map[mw.ustring.lower(found_proj_name)] then
match_found = true
break
end
end
if match_found then
local formatted_article_link = item_prefix .. article_name_display .. item_suffix
table.insert(output_items, formatted_article_link)
end
end
if #output_items == 0 then
return args.no_match_msg or "暂无符合指定专题的候选项目。"
end
local result_list = {}
for i, item in ipairs(output_items) do
table.insert(result_list, "# " .. item)
end
return table.concat(result_list, "\n")
end
return p