模块:BusRoutes/utilities

求闻百科,共笔求闻
文档图示 模块文档[创建] [跳转到代码]

本模块还没有文档页面。

您可以创建文档以让用户更好地理解本模块的用途。
编者可以在本模块的沙盒创建 | 镜像和测试样例创建页面进行实验。
请将模块自身所属的分类添加在文档中。本模块的子页面
local p = {}

--[[
	array 是一个非空的数组,其各项均为 table。截取其 id 和 aliases 的内容,作为表的键。
	例如,如果 array 的值为 { {id = 'a', aliases = {'b', 'c'} } },那么
	处理之后,这个 array.a、array.b、array.c 的值都会是 array[1] 的值。
	其中各项的 aliases 字段时可选的。
	之所以先使用数组,是为了以便于此后按顺序迭代,而非按照默认的 pairs 的顺序按照散列迭代。
	该函数会修改参数 array 的值,并返回它。
]]
function p.complete_index(array)
	if type(array) ~= 'table' then
		error('无法调用complete_index,因为' .. tostring(array) .. '的类型不为table')
	end
	
	for i, item in ipairs(array) do
		if type(item) ~= 'table' then
			error('错误:表的第' .. i .. '项(' .. tostring(item) .. ')' .. '的数据类型不为table')
		end
		local id = item.id
		if not id then
			-- 忽略没有 id 的情况。
		elseif type(id) == 'number' then
			error('错误:表的第' .. i .. '项的id(' .. tostring(id) .. ')' .. '的数据类型不可以是number')
		else
			array[id] = item
		end
		
		local aliases = item.aliases
		if not aliases then
			-- 忽略没有 aliases 的情况。
		elseif type(aliases) == 'table' then
			for _, alias in ipairs(aliases) do
				if not alias then
				elseif type(alias) == 'number' then
					error('错误:表的第' .. i .. '项的alias中不应包含number数据类型:' .. tostring(alias))
				else
					array[alias] = item
				end
			end
		elseif type(aliases) == 'number' then
			error('错误:表的第' .. i .. '项的alises(' .. tostring(aliases) .. ')' .. '的数据类型不可以是number')
		end
	end
	
	return array
end

--[[
	格式化字符串,例如:
	p.format('$1和$2', 'first', 'second') → first和second
	p.format('$1和$2', {'first', 'second'}) →  first和second
	p.format('$a和$b', {a = 'first', b = 'second'}) → first和second
]]
function p.format(fs, args, ...)
	if type(args) ~= 'table' then
		args = {args, ...}
	end
	return string.gsub(fs, '%$(%w+)', function (capture)
		return args[tonumber(capture) or capture]
	end)
end

--[[
	创建一个由两个表组合的表。
	返回的这个表在索引时,如果 t1 中的键不存在(不包括为 false),则尝试访问 t2 中的。
	返回的表是根据元表控制的,并不会实际复制表的内容。
	例如,t1 = {a = 'A', b = 'B', c = 'C'}
		  t2 = {b = '2', c = '3', d = '4'}
		  t3 = fallbackTable(t1, t2)
	那么,t3.a = 'A', t3.b = 'B', t3.d = '4'。
]]
function p.fallbackTable(t1, t2)
	if not t1 then
		-- 一项都没有,返回空。
		return t2 or t1
	end
	if not t2 then
		-- 只有一项,返回这一项。
		return t1
	end
	
	return setmetatable({}, {
		__index = function(self, key)
			local v1 = t1[key]
			if v1 == nil then
				return t2[key]
			else
				return v1
			end
		end
	})
end

--[[
	判断某个元素是否在一个数组内,或者自身与它相等。
	例如inArray('a', 'a') => true
		inArray('a', {'a', 'b'}) => true
		inArray('a', {'c', 'd'}) => true
	判断相等是根据的“==”运算符。
]]
function p.inArray(element, array)
	if element == array then return true end
	if type(array) == 'table' then
		for _, v in ipairs(array) do
			if v == element then return true end
		end
	end
	return false
end

--[[
	判断 elements 中的任意一个元素是否在 array 中。
	elements 和 array 都可以是数组,也可以是其他类型。
]]
function p.anyInArray(elements, array)
	if p.inArray(elements, array) then return true end
	if type(elements) == 'table' then
		for _, element in ipairs(elements) do
			if p.inArray(element, array) then return true end
		end
	end
	return false
end

--[[
	判断字符串能否找到匹配的正则表达式,或者正则表达式列表中的任何一个。
	@string s
	@string|table patterns
]]
function p.matchAnyOf(s, patterns)
	if type(s) ~= 'string' and type(s) ~= 'number' then
		error ('参数 s 的必须是字符串,而不是' .. tostring(s))
	end
	if type(patterns) == 'string' or type(patterns) == 'number' then
		return mw.ustring.match(s, patterns)
	elseif type(patterns) == 'table' then
		for _, pattern in ipairs(patterns) do
			if type(pattern) == 'string' or type(pattern) == 'number' then
				local match = mw.ustring.match(s, pattern)
				if match then return match end
			else
				error ('参数 patterns 中包含非字符串值:' .. tostring(pattern))
			end
		end
		return nil
	else
		error ('参数 patterns 必须是字符串或者列表,而非' .. tostring(patterns))
	end
end

--[[
	array 和 patterns 应该至少一个不为 nil。
]]
function p.inArrayOrMatchAnyOf(elements, array, patterns)
	return (array and p.inArray(elements, array))
	or (patterns and (type(elements) == 'string' or type(elements) == 'nunmber') and p.matchAnyOf(elements, patterns))
end

function p.tryLoadData(name)
	local successes, data = pcall(mw.loadData, name)
	if successes then
		return data
	else
		mw.log("无法加载" .. tostring(name) .. "中的数据,原因:" .. tostring(data))
	end
end

function p.tryLoadJsonData(name)
	local successes, data = pcall(mw.loadJsonData, name)
	if successes then
		return data
	else
		mw.log("无法加载" .. tostring(name) .. "中的数据,原因:" .. tostring(data))
	end
end

--[[
	strings 是由字符串组成的数组。
	例如:
	{'a', 'b', '!c', '!d'} => {'a', 'b'}, {'c', 'd'}
	注意:返回的空表会转化为 nil
]]
function p.splitPrefixedStrings(strings, prefix)
	if not strings then return nil end
	local ret1, ret2 = {}, {}
	local i = #prefix
	for _, s in ipairs(strings) do
		if s:sub(1, i) == prefix then
			ret2[#ret2 + 1] = s:sub(i + 1)
		else
			ret1[#ret1 + 1] = s
		end
	end
	return (#ret1 > 0 and ret1 or nil), (#ret2 > 0 and ret2 or nil)
end

return p