跳转到内容

模組:沙盒/PexEric/1

维基百科,自由的百科全书

这是本页的一个历史版本,由PexEric留言 | 贡献2025年5月31日 (六) 18:50编辑。这可能和当前版本存在着巨大的差异。

local p = {}

-- 依赖模块
local Arguments = require('Module:Arguments')
local TPV = require('Module:Template parameter value') -- Template Parameter Value

-- WikiProject banner shell 及其重定向的Lua正则表达式列表 (小写处理,匹配时会忽略大小写)
-- 这些模式用于 Module:Template parameter value
local WPBANNER_SHELL_PATTERNS = {
	"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",
	"[維维]基[专專][题題][橫横]幅", 
	"多?[個个]?[維维]?基?[专專][题題][橫横]幅",
	"[維维]基[专專][题題]", 
	"多?[個个]?[維维]?基?[专專][题題]",
	"[专專][题題][橫横]幅", 
	"通用[評评][級级]",
}

-- 内部函数:从页面内容中获取候选项目列表
-- 基于 Module:PatternedCandidateUtils 的 getCandidates 逻辑
local function _getCandidatesInternal(args_table)
	local page_title_str = args_table.title
	if not page_title_str or page_title_str == '' then
		return {} -- 没有提供页面标题
	end

	local title_obj = mw.title.new(page_title_str)
	if not title_obj or not title_obj.exists then
		return {} -- 页面不存在
	end

	local page_content = title_obj:getContent()
	if not page_content then
		return {} -- 获取页面内容失败
	end

	local matches = {}
	local black = {} -- 黑名单
	if args_table.black then
		for b in mw.text.gsplit(args_table.black, '|', true) do
			black[b] = true
		end
	end

	local pattern = args_table.pattern
	if not pattern or pattern == '' then
		return {} -- 没有提供匹配模式
	end

	-- 替换 MediaWiki 模板语法到 Lua 模式
	pattern = pattern:gsub('%%{{!', '{{')
	pattern = pattern:gsub('%%}}', '}}')
	pattern = pattern:gsub('%%{{', '{') --  %{{ -> {
	pattern = pattern:gsub('%%}}', '}') --  %}} -> }

	for m in mw.ustring.gmatch(page_content, pattern) do
		local clean_m = mw.text.trim(m) -- 清理可能捕获到的空白
		-- 如果模式捕获的是类似 [[Article|Display]] 或 [[Article]] 的内容,尝试提取真实条目名
		-- 这是一个基本清理,更复杂的清理应由 pattern 本身完成
		clean_m = mw.ustring.gsub(clean_m, "^%[%[([^%]|]+)|.+%]%]$", "%1") -- [[Article|Display]] -> Article
		clean_m = mw.ustring.gsub(clean_m, "^%[%[([^%]]+)%]%]$", "%1")    -- [[Article]] -> Article

		if not black[clean_m] and not (args_table.blackregex and mw.ustring.match(clean_m, args_table.blackregex)) then
			table.insert(matches, clean_m)
		end
	end
	return matches
end

-- 内部函数:获取指定条目的所属专题列表
local function _getProjectsForArticle(article_title_str)
	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_obj = article_title_obj:getTalkPage()
	if not talk_page_title_obj or not talk_page_title_obj.exists then
		return {} -- 讨论页不存在
	end

	-- 使用 Module:Template parameter value 获取参数 '1'
	-- WPBANNER_SHELL_PATTERNS 包含所有 WikiProject banner shell 的重定向 (作为正则表达式)
	local success, banner_shell_content = TPV.getParameter(
		talk_page_title_obj.prefixedText,
		WPBANNER_SHELL_PATTERNS,
		'1', -- 匿名参数1
		{ treat_as_regex = true, ignore_blank = true } -- 模板名列表是正则表达式,忽略空参数
	)

	if not success or not banner_shell_content or banner_shell_content == '' then
		return {} -- 未找到专题横幅或参数1为空
	end

	local projects = {}
	-- 从参数内容中提取模板名,例如 {{模板名1}}{{模板名2|参数=值}}
	-- 这个 gmatch 会尝试匹配 {{...}} 结构,然后提取花括号后的第一个非空白、非管道符、非等号的序列作为模板名
	for template_invocation in mw.ustring.gmatch(banner_shell_content, "{{.-}}") do
		-- 提取模板名:{{ 开头,后面跟非 | 和 } 的字符,直到 | 或 }}
		local project_name = mw.ustring.match(template_invocation, "{{%s*([^}|]+)")
		if project_name then
			project_name = mw.text.trim(project_name)
			if project_name ~= "" then
				table.insert(projects, project_name)
			end
		end
	end
	return projects
end

-- 主要函数1:以表格形式列出某个特定内容评选中所有候选项目对应的所属专题
function p.listProjectsForCandidates(frame)
	local args = Arguments.getArgs(frame)

	local candidates_fetch_args = {
		title = args.title,
		pattern = args.pattern,
		black = args.black,
		blackregex = args.blackregex
	}

	local candidates = _getCandidatesInternal(candidates_fetch_args)

	if #candidates == 0 then
		return args.no_candidates_text or "''当前没有候选项目。''"
	end

	local item_prefix = args.item_prefix or ""
	local item_suffix = args.item_suffix or ""
	local project_name_prefix = args.project_prefix or "{{tl|" -- 默认使用 {{tl|}} 包裹专题名
	local project_name_suffix = args.project_suffix or "}}"
	local linkprefix = args.linkprefix or "" -- 用于生成候选项目链接的前缀

	local output_table = {'{| class="wikitable sortable candidate-projects-table"'}
	table.insert(output_table, '! 候选项目 !! 所属专题')

	for _, candidate_name in ipairs(candidates) do
		local display_candidate_name = candidate_name:gsub("_", " ") -- 链接显示时替换下划线为空格
		local linked_candidate_name
		if linkprefix ~= "" then
			linked_candidate_name = '[[:' .. linkprefix .. candidate_name .. '|' .. display_candidate_name .. ']]'
		else
			linked_candidate_name = '[[:' .. display_candidate_name .. ']]'
		end
		local wrapped_candidate_name = item_prefix .. linked_candidate_name .. item_suffix

		local projects = _getProjectsForArticle(candidate_name)
		local projects_str
		if #projects > 0 then
			local formatted_projects = {}
			for _, proj_name in ipairs(projects) do
				table.insert(formatted_projects, project_name_prefix .. proj_name .. project_name_suffix)
			end
			projects_str = table.concat(formatted_projects, '、') -- 使用顿号分隔
		else
			projects_str = args.no_projects_text or "''暂无专题''"
		end
		table.insert(output_table, '|-\n| ' .. wrapped_candidate_name .. ' || ' .. projects_str)
	end

	table.insert(output_table, '|}')
	return table.concat(output_table, '\n')
end

-- 主要函数2:获取特定内容评选栏目中指定的属于一个或多个给定专题的候选项目
function p.filterCandidatesByProjects(frame)
	local args = Arguments.getArgs(frame)

	local candidates_fetch_args = {
		title = args.title,
		pattern = args.pattern,
		black = args.black,
		blackregex = args.blackregex
	}
	local candidates = _getCandidatesInternal(candidates_fetch_args)

	if #candidates == 0 then
		return args.no_candidates_text or "''当前没有候选项目。''"
	end

	-- 收集 projectN 参数作为正则表达式
	local project_patterns = {}
	local i = 1
	while true do
		local proj_arg_name = 'project' .. i
		if args[proj_arg_name] then
			table.insert(project_patterns, args[proj_arg_name])
		else
			-- 检查是否存在 project(无数字后缀),作为 project1 的别名
			if i == 1 and args.project then
				table.insert(project_patterns, args.project)
			else
				break -- 没有更多的 projectN 参数了
			end
		end
		i = i + 1
	end

	if #project_patterns == 0 then
		return "''错误:未指定任何专题进行筛选(缺少 project 或 project1 等参数)。''"
	end

	local item_prefix = args.item_prefix or ""
	local item_suffix = args.item_suffix or ""
	local linkprefix = args.linkprefix or ""

	local matched_candidates_output = {}

	for _, candidate_name in ipairs(candidates) do
		local article_projects = _getProjectsForArticle(candidate_name)
		local found_match_for_this_candidate = false

		if #article_projects > 0 then
			for _, actual_project_name in ipairs(article_projects) do
				for _, pattern_to_match in ipairs(project_patterns) do
					-- mw.ustring.match 返回非nil即为匹配成功
					if mw.ustring.match(actual_project_name, pattern_to_match) then
						found_match_for_this_candidate = true
						break -- 当前条目的一个专题已匹配一个模式,无需再检查此条目的其他专题或模式
					end
				end
				if found_match_for_this_candidate then
					break -- 已找到匹配,跳出外层专题循环
				end
			end
		end

		if found_match_for_this_candidate then
			local display_candidate_name = candidate_name:gsub("_", " ")
			local linked_candidate_name
			if linkprefix ~= "" then
				linked_candidate_name = '[[:' .. linkprefix .. candidate_name .. '|' .. display_candidate_name .. ']]'
			else
				linked_candidate_name = '[[:' .. display_candidate_name .. ']]'
			end
			local wrapped_candidate_name = item_prefix .. linked_candidate_name .. item_suffix
			table.insert(matched_candidates_output, wrapped_candidate_name)
		end
	end

	if #matched_candidates_output > 0 then
		return '# ' .. table.concat(matched_candidates_output, '\n# ') -- 输出为 # 号列表
	else
		return args.no_filtered_results_text or "''没有找到符合指定专题条件的候选项目。''"
	end
end

return p