模块:CGroup

求闻百科,共笔求闻

本模块用于实现公共转换组(public conversion group)。公共转换组可用于多个页面共用同一组繁简转换(包括地区词转换)规则。本模块的子页面将会存放各公共转换组的数据(及其文档页面),这些公共转换组用于模板链接:{{NoteTA}}。参见Help:字词转换处理

公共转换组模块格式

公共转换组模块是Module:CGroup的子页面,存储一系列指定格式的转换规则(见下)。模板链接:{{NoteTA}}模板用于在页面中实现这些繁简转换规则。

每个公共转换组模块返回的值都是一个表,其存在以下字段:

  • name:该转换组的名称,通常与模块名称相同。例如Module:CGroup/IT的name就是IT。
  • description:简要描述该转换组。可以使用维基文本,但是不能包含模板、解析器函数和魔术字(如需使用,请直接在模块内调用并返回值)。
  • content:该转换组的内容。是一个列表。列表的每一项都可以是如下的任意一个格式:
    • 普通转换规则:
    • {type='item', original='原文', rule='转换规则'},表示一个普通的转换规则。其中“原文”是指的该词对应的外文名称,转换规则则是类似-{H|转换规则}-中的转换规则。例如{type='item', original='user', rule='zh-cn:用户;zh-tw:使用者'}。original的值可以为空。
    • '转换规则',即上述写法的简写形式,相当于{type='item', rule='转换规则'},不提供original字段。
    • {'转换规则'}{'原文', '转换规则'},同上,是上述写法的简写形式。
      文字注释:
    • {type='text', text='一段文字'},用于在模块文档呈现结果中显示一段文字,不会应用于公共转换组。实际应用中,主要用于将不同的转换规则归到不同的段落标题下,从而进行分类。
      导入转换规则:
    • {type='import', import='转换组名称'},导入另一个转换组。该转换组将包含另一个转换组中的所有转换规则。请谨慎使用。
    • {import='转换组名称'},上述写法的简写形式。
      增强的普通转换规则:
    • {type='variants', ['变体名称']=文字, ...},类似于item,但是所有转换规则的内容是结构化的,以便于模块进行解析。例如,{type='variants', cn='用户', hk='用户', tw='使用者'}就大致相当于{type='item', rule='zh-cn:用户;zh-hk:用户;zh-tw:使用者'}。但这种用法暂时无法实现单向转换。

子页面列表

上述文档内容嵌入自Module:CGroup/doc编辑 | 历史
编者可以在本模块的沙盒创建 | 镜像和测试样例创建页面进行实验。
请将模块自身所属的分类添加在文档中。本模块的子页面
-- 本模块的子页面为求闻百科的公共转换组。
local p = {}
local _mt = {__tostring=table.concat}
local _mt2 = {__tostring=function(self) return table.concat(self, '\n') end}

local langcodes = {
	'zh-hans', 'zh-cn', 'zh-sg', 'zh-my',
	'zh-hant', 'zh-tw', 'zh-hk', 'zh-mo',
	zh = 'zh',
	hans = 'zh-hans',
	cn = 'zh-cn',
	sg = 'zh-sg',
	my = 'zh-my',
	hant = 'zh-hant',
	tw = 'zh-tw',
	hk = 'zh-hk',
	mo = 'zh-mo',
}
local bcp47s = {
	'zh-hans', 'zh-hans-cn', 'zh-hans-sg', 'zh-hans-my', 
	'zh-hant', 'zh-hant-tw', 'zh-hant-hk', 'zh-hant-mo',
	['zh'] = 'zh',
	['zh-hans'] = 'zh-hans',
	['zh-hant'] = 'zh-hant',
	['zh-cn'] = 'zh-hans-cn',
	['zh-sg'] = 'zh-hans-sg',
	['zh-my'] = 'zh-hans-my',
	['zh-tw'] = 'zh-hant-tw',
	['zh-hk'] = 'zh-hant-hk',
	['zh-mo'] = 'zh-hant-mo',
}


function p.load(name)
	local moduleTitle = mw.title.makeTitle('Module', 'CGroup/' .. name)
	if moduleTitle and moduleTitle.exists then
		return mw.loadData(tostring(moduleTitle))
	else
		error ('错误:没有' .. name .. '这个模块,请确保[[' .. tostring(moduleTitle) .. ']]页面存在。')
	end
end

-- 处理一条类型为variants的规则。
local function variants(pieces, v)
	local node = {}
	for langcode, text in pairs(v) do
		if langcodes[langcode] then
			node[#node+1] = langcodes[langcode]
			node[#node+1] = ':'
			node[#node+1] = text
			node[#node+1] = ';'
		end
	end
	return table.concat(node)
end

function p.parseRulePiece(rulepiece)
	rulepiece = mw.text.trim(rulepiece)
	if rulepiece=='' then return nil end
	local part1, part2 = mw.ustring.match (rulepiece, "(.-)%s*=>%s*(.-)")
		-- 例如,如果 rulepiece 为 '數碼=>zh-cn:数字'
		-- 则part1, part2 = '數碼', 'zh-cn:数字'
	if not part1 then
		part2 = rulepiece
		-- 例如,如果 rulepiece 为 'zh-tw:裝置'
		-- 则part1, part2 = nil, 'zh-tw:裝置'
	end
	local part3, part4 = mw.ustring.match (part2, "(.-)%s*%:%s*(.+)")
		-- 例如,如果 part2 为 'zh-tw:裝置'
		-- 则part3, part4 = 'zh-tw', '裝置'
	return part1, part2, part3, part4
end

-- 将rule转化为特定langcode的值。
-- 例如:
-- @langcode 'zh-hans'
-- @rule 'zh-hans:矩阵浪潮;zh-hant:矩陣;'
-- 此情况下,pieces后面会加上一个 '矩陣=>矩阵浪潮;'
function p.convertRule(langcode, rule, pieces)
	pieces = pieces or setmetatable({}, _mt)
	assert(langcode, '缺失参数:langcode')
	assert(rule, '缺失参数:rule')
	local langcode2text = {}
	for rulepiece in mw.text.gsplit(rule, ';%s*') do
		local part1, part2, part3, part4 = parseRulePiece(rulepiece)
		if part1 and part4 and part3==langcode then
			pieces[#pieces+1] = string.format('* %s => %s;', part1, part4)
		elseif part3 then
			langcode2text[part3] = part4
		end
	end
	local targetText = langcode2text[langcode]
	if targetText then
		for langcode2, text in pairs(langcode2text) do
			if langcode ~= langcode2 and text ~= targetText then
				pieces[#pieces+1] = string.format('* %s => %s;', text, targetText)
			end
		end
	end
	return pieces
end

-- 将模块数据转化成由多个-{H|规则}-组成的维基文本。
-- @table data 可能是由mw.loadData导出的数据,因此是只读的,表操作和井号不可用。
function p.toWikitext(data, pieces)
	pieces = pieces or setmetatable({}, _mt)
	if not (data and data.content) then return end
	for i, v in ipairs(data.content) do
		local rule
		if type(v)=='string' then
			rule = v
		elseif type(v)~='table' then
			error('无法识别公共转换组' .. (data.name or '') .. '中的数据,因为其类型为' .. type(v))
		elseif v.type == 'item' then
			-- v格式为	'规则' 或
			--			{rule = '规则内容'} 或
			--			{type='item', rule='规则内容'} 或
			--			{'规则内容'} 或
			--			{'原文', '规则内容'}
			rule = v.rule
		elseif v.type == 'import' then
			-- v格式为	{import = '名称'} 或
			--			{type='import', name='名称'}
			local name = v.name
			p.toWikitext(p.load(name), pieces)
		elseif v.type == 'variants' then
			rule = variants(pieces, v)
		elseif not v.type then
			-- 根据表字段自动识别。
			-- 如果v[2]或v[1]存在,则视为一个item。
			-- 如果v.import,则视为一个import。
			-- 要处理大量数据,为确保性能,不把每一个细节都做成函数。
			rule = v[2] or v[1] or v.rule
			if v.import then
				p.toWikitext(p.load(v.import), pieces) -- 这个pieces通常应该不是空表。
			end
			-- 如果有在langcodes中存在的对应的字段,则执行variants。
			-- 例如langcodes中有zh,如果v.zh存在,则执行variants(pieces, v)。
			local bool = false
			for may_be_langcode,_ in pairs(v) do
				if langcodes[may_be_langcode] then
					bool = true
					break
				end
			end
			if bool then
				-- 此时视为variants类型的规则。
				rule = variants(pieces, v)
			end
		end
		if rule then
			pieces[#pieces+1] = '-{H|' .. rule .. '}-'
		end
	end
	return pieces
end

function p.convert(data, langcode, pieces)
	pieces = pieces or setmetatable({}, _mt2)
	if not (data and data.content) then return end
	for i, v in ipairs(data.content) do
		local rule
		if type(v)=='string' then
			rule = v
		elseif type(v)~='table' then
			error('无法识别公共转换组' .. (data.name or '') .. '中的数据,因为其类型为' .. type(v))
		elseif v.type == 'item' then
			rule = v.rule
		elseif v.type == 'import' then
			local name = v.name
			p.convert(p.load(name), langcode, pieces)
		elseif v.type == 'variants' then
			rule = variants(pieces, v) -- 以后肯定不会在这里调用variants的
		elseif not v.type then
			rule = v[2] or v[1] or v.rule
			if v.import then
				p.convert(p.load(v.import), langcode, pieces) -- 这个pieces通常应该不是空表。
			end
			local bool = false
			for may_be_langcode,_ in pairs(v) do
				if langcodes[may_be_langcode] then
					bool = true
					break
				end
			end
			if bool then
				-- 此时视为variants类型的规则。
				rule = variants(pieces, v)
			end
		end
		if rule then
			p.convertRule(langcode, rule, pieces)
		end
	end
	return pieces
end

local function prettyprintItem(original, rule)
	if original then
		return string.format('* 原文:%s;-{D|%s}-当前显示为:-{|%s}-',
			original,
			rule,
			rule)
	else
		return string.format('* -{D|%s}-当前显示为:-{|%s}-',
			rule,
			rule)
	end
end

function p.prettyprint(data, pieces)
	pieces = pieces or setmetatable({}, _mt2)
	for i, v in ipairs(data.content) do
		if type(v)=='string' then
			pieces[#pieces+1] = prettyprintItem(nil, v)
		elseif type(v)~='table' then
			error('无法识别公共转换组' .. (data.name or '') .. '中的数据,因为其类型为' .. type(v))
		elseif v.type == 'text' then
			pieces[#pieces+1] = v.text
		elseif v.type == 'item'then
			pieces[#pieces+1] = prettyprintItem(v.original, v.rule)
		elseif v.type == 'import' then
			p.prettyprint(p.load(v.import), pieces)
		elseif v.type == 'variants' then
			pieces[#pieces+1] = prettyprintItem(v.original, variants(pieces, v))
		elseif not v.type then
			if v[1] then
				pieces[#pieces+1] = v[2] and prettyprintItem(v[1], v[2]) or prettyprintItem(nil, v[1])
			elseif v.rule then
				pieces[#pieces+1] = p.prettyprintItem(v.original, v.rule)
			elseif v.import then
				p.convert(p.load(v.import), langcode, pieces) -- 这个pieces通常应该不是空表。
			elseif v.text then
				pieces[#pieces+1] = v.text
			end
			local bool = false
			for may_be_langcode,_ in pairs(v) do
				if langcodes[may_be_langcode] then
					bool = true
					break
				end
			end
			if bool then
				-- 此时视为variants类型的规则。
				pieces[#pieces+1] = prettyprintItem(v.original, variants(pieces, v))
			end
		end
	end
	return pieces
end

return p