2023年政策修订增补工作正在进行中,欢迎参与!
  • Moegirl.ICU:萌娘百科流亡社群 581077156(QQ),欢迎对萌娘百科运营感到失望的编辑者加入
  • Moegirl.ICU:账号认领正在试运行,有意者请参照账号认领流程

Module:Sandbox/公的驱逐舰/LUM

萌娘百科,万物皆可萌的百科全书!转载请标注来源页面的网页链接,并声明引自萌娘百科。内容不可商用。
跳转到导航 跳转到搜索
Template-info.svg 模块文档  [创建] [刷新]
--[[
	LUM 暂且解作 Lua Utilities Module, 即"Lua 实用模块".
	本模块期望提供一些 Lua 和 Scribunto 没有提供, 但是对模块编写(特别是处理模板输入)有很大帮助的函数.
	本模块期望能由多名对Lua较熟悉的用户一同维护; 目前的主要编者是 U:公的驱逐舰, 另获得了 U:Maya-Maja-Maia 的大力协助.
	因为是16开始写的, 所以 Gotta praise the Crocc!

	以下参与了模块编撰的作者已决定将他们在本模块的编辑通过 CC BY 4.0 释出:
		U:公的驱逐舰  U:Maya-Maja-Maia
	仅包含以上作者的贡献的测试版本目前保留在中文萌娘百科的 Module:Sandbox/公的驱逐舰/LUM.

	本模块的文档目前直接以注释的形式写在模块源代码内.
	函数语法采用 func ( type, type, ... ) 或 func ( arg=type, arg1=type [ , arg2=type [ , arg3 = type ... ] ] ) 等方式记录, 其中, 
	等号左边是参数名、右边是函数期待的参数类型; 方括号内代表可选参数; 省略号代表可按格式重复的部分.
	"可使用命名参数表"的函数可只接受一个包含所有所需参数的 table 作为输入, 其 key 即为语法中定义的参数名称.
	"只可使用命名参数表"的函数即如其名.
	不能使用命名参数表的简单函数不命名参数, 直接列出所需参数的类型.

	推荐使用方法:在模块中加入
	local lum = require('Module:LUM')
	即可.
]]


local lum = {}

-------- 简单函数 Simple Functions --------

	-- isEmpty ( string ). 返回 boolean.
	lum.isEmpty = function ( s ) return ( s == '' or s == nil ) end
	
	-- tableItemOrDefault ( table [ , variable [ , variable ] ] ). 返回值取决于 t, t 的子项或 default.
	lum.tableItemOrDefault = function ( t, default, key ) key = key or 1 return ( t and t[key] ) or default end
	
	lum.firstOrDefault = function ( t, default ) return lum.tableItemOrDefault ( t, default ) end -- for the lolz

-------- 比较函数 Comparator --------
	
	lum.comp = {}
	
	lum.comp.isAscending = function ( sign )
		sign = (sign or ''):lower()
		return not ( sign == '>' or sign == '-' or sign == 'desc' or sign == 'd' )
	end
	
	lum.comp.numThenString = function ( sign )
		sign = lum.comp.isAscending ( sign )
		return function ( a, b )
			if		type ( a ) == 'number' and type ( b ) == 'string' then return true
			elseif	type ( b ) == 'number' and type ( a ) == 'string' then return false
			else return sign == ( a < b ) end
		end
	end
	lum.comp.nts = lum.comp.numThenString
	
	lum.comp.stringThenNum = function ( sign )
		sign = lum.comp.isAscending ( sign )
		return function ( a, b )
			if		type ( a ) == 'number' and type ( b ) == 'string' then return false
			elseif	type ( b ) == 'number' and type ( a ) == 'string' then return true
			else return sign == ( a < b ) end
		end
	end
	lum.comp.stn = lum.comp.numThenString
	
	lum.comp.tableElement = function ( sign, key, default, comp )
		sign = lum.comp.isAscending ( sign )
		key = key or 1
		default = default or ''
		comp = comp or function ( a, b ) return a < b end
		return function ( a, b ) return sign == comp ( ( a[key] or default ), ( b [key] or default ) ) end
	end
	lum.comp.te = lum.comp.tableElement
	
	lum.comp.tableElementOrSelf = function ( sign, key, default, comp )
		sign = lum.comp.isAscending ( sign )
		key = key or 1
		default = default or ''
		comp = comp or function ( a, b ) return a < b end
		return function ( a, b ) return sign == comp ( ( a[key] or a or default ), ( b [key] or b or default ) ) end
	end
	lum.comp.teOrSelf = lum.comp.tableElementOrSelf


-------- 函数协助 Function Helper --------

	--[[ enablePackedArgs ( func=function, aliasNames=table [ , cond=function ] ); 可使用命名参数表; 别名 epa.
		编写维护责任人: User:Maya-Maja-Maia.
		返回一个 function.
		本函数将不可使用命名参数表的输入函数 func 转化为可以使用命名参数表的函数并输出.
		aliasNames 应按序存放命名参数表中的参数名字.
		cond 接受函数的完整参数表作为输入, 判断是否应当将第一个参数视为命名参数表. 返回类型应当是 boolean.
		cond 未定义时, 默认为判断参数表是否只有一个参数.
	]]
	lum.enablePackedArgs = function ( func, aliasNames, cond )
		cond = cond or function ( args ) return #args == 1 end
		return function ( ... )
			local packedArgs = {}
			if cond( arg ) then 
				for ite = 1, #aliasNames do
					packedArgs[ite] = arg[1][aliasNames[ite]]
				end
			else
				packedArgs = arg
			end
			--mw.logObject ( packedArgs, 'epa: packedArgs' )
			return func( unpack( packedArgs, 1, math.max(#packedArgs, #aliasNames) ) )
		end
	end
	
	lum.enablePackedArgs = lum.enablePackedArgs( lum.enablePackedArgs, { 'func', 'aliasNames', 'cond' } )
	
	lum.epa = lum.enablePackedArgs
	
	
-------- 参数处理 Argument Processing --------

	--[[ getArgFromAliases ( args=table, aliasTable=table [ , default=any [ , func=function ] ] ); 可使用命名参数表; 别名 gafa.
		返回值类型取决于 args 和 default.
		本函数按照 aliasTable 的顺序在 args 中寻找指定别名的参数, 并返回第一个 func 判断为 true 的参数本身; 
		如果用尽了 aliasTable 也没有符合 func 要求的参数, 则返回 default.
		default 未定义时默认为 nil.
		func 未定义时默认为 function ( a ) return a ~= nil end; 即未定义 func 时, 本函数会返回第一个不为 nil 的参数.
		func 会被按序提供两个输入:arg(类型取决于 args)和 alias(类型取决于 aliasTable); func 的返回类型应当是 boolean.
		考虑到函数设计用途, func 应当有处理 nil 输入的能力.
	]]
	lum.getArgFromAliases = function ( args, aliasTable, default, func )
		func = func or function ( a ) return a ~= nil end
		for i=1, #aliasTable do
			if func ( args[ aliasTable[i] ], aliasTable[i] ) then return args[ aliasTable[i] ] end
		end
		return default
	end
	lum.getArgFromAliases = lum.epa( lum.getArgFromAliases, { 'args', 'aliasTable', 'default', 'func' } )
	lum.gafa = lum.getArgFromAliases

	--[[ getNonEmptyArgFromAliases ( args=table, aliasTable=table, [default=any] ); 可使用命名参数表; 别名 gneafa.
		返回值类型取决于 args 和 default.
		本函数按照 aliasTable 的顺序在 args 中寻找指定别名的参数, 并返回第一个不为空字符串或 nil 的参数本身; 
		如果用尽了 aliasTable 也没有符合 func 要求的参数, 则返回 default.
		default 未定义时默认为 nil.
	]]	
	lum.getNonEmptyArgFromAliases = function ( args, aliasTable, default ) return lum.gafa ( args, aliasTable, default, function ( a ) return not lum.isEmpty( a ) end ) end
	lum.getNonEmptyArgFromAliases = lum.epa( lum.getNonEmptyArgFromAliases, { 'args', 'aliasTable', 'default' } )
	lum.gneafa = lum.getNonEmptyArgFromAliases		
		
	--[[ 
	很可惜, gabp还不能用. 迟些时候再修...
	getArgsByPattern ( args=table, ptn=string [ , keyMorph=function [ , comp=function ] ] ); 可使用命名参数表; 别名 gabp.
		返回值为 table.
		本函数尝试在 args 中寻找参数名称符合 ptn 定义的 ustring pattern 的参数, 并将其存入返回的 table 中.
		返回值会是一个无名有序列表; 若本函数找不到符合的参数, 那么这个表将会是一个空表.
		本函数会尝试使用 comp 函数为其排序, 方法如下:
			找寻到的参数名(若 ptn 无 capture)/ ptn 的 capture(若有 capture)会被包装成一个无名有序 table 并被提供给 keyMorph;
			keyMorph 应当将输入转换成一个能够被 comp 接受的形式;
			comp 将对转换后的参数名/capture 排序, 然后使用这个排序来排序实际的参数数据. 转换后的参数名/capture 最终会被丢弃.
		comp 未定义时默认为 function ( a, b ) return a < b end; 若参数可以是乱序的, 可考虑将 comp 定义为 "function () return false end" 来最大化输入兼容性.
		keyMorph  未定义时默认为 function ( t ) return table.concat( t ) end.

	lum.getArgsByPattern = function ( args, ptn, comp, keyMorph )
		comp = comp or function ( a, b ) return a < b end
		keyMorph = keyMorph or function ( t ) return table.concat( t ) end
		local p = function (...)
			local r = true
			if #arg > 2 then table.remove ( arg, 1 ) table.remove ( arg, 1 ) end
			return arg[1], ( r and arg or nil )
		end
		local keys = {} local hold = {} local out = {}
		for k, v in pairs ( args ) do
			local found, keyTable = p ( mw.ustring.find ( k, ptn ) )
			if found then
				key = keyMorph ( keyTable or { k } )
				keys[#keys+1] = key
				hold[key] = v 
			end
		end
		comp = comp or function ( a, b ) return a < b end
		table.sort ( keys, comp )
		for i = 1, #hold do
			out[#out+1] = hold[ keys[i] ]
		end
		return out
	end
	lum.getArgsByPattern = lum.epa( lum.getArgsByPattern, { 'args', 'ptn', 'comp', 'keyMorph' } )
	lum.gabp = lum.getArgsByPattern
	]]

	--[[ parseArray ( str=string [ , flatten=boolean ] ); parseArray { 1=string [ , flatten=boolean ] }; 可使用命名参数表; 别名 parseTable.
		返回值为 table, string, 或 nil.
		本函数尝试将 str 分割成一个无名有序列表. str 的语法如下:
			";"或者";" (全角) 是"一级分隔符"; "\"或者"、"是"二级分隔符". 
			每个一级项之间应用一级分隔符分隔, 如 "a;b;c" 或 "a\;b\;c\;" 会被分割为 { {"a"}, {"b"}, {"c"} };
			每个一级项内可包含若干二级项、以二级分隔符分隔, 如 "a1\a2;b;c1\c2\c3" 或 "a1\a2\;b\;c1\c2\c3\;" 会被分割为 { {"a1","a2"}, {"b"}, {"c1","c2","c3"} };
			当一个项位于字符串或一级项之末尾时, 可以省略末尾的对应分隔符.
			本函数能够处理空项, 并会将其转换成空字符串; 但是, 空项在字符串或一级项之末尾, 且其之前有非空项时, 不得省略末尾的对应分隔符, 如 "a;;" 或 "a\;\;" 会被分割为 { {"a"}, {""} }; ";b1\\" 或 "\;b1\\;" 会被分割为 { {""}, {"b1",""} }; 
		本函数包含一个默认禁用的 flatten 功能. 启用时, 若每一个一级项内均只包含一个二级项, 那么一级项的 table 会被舍弃、替换成二级项本身; 若返回的 table 只包含一个一级项, 那么返回值会舍弃这个 table、直接返回一级项本身. 如:
			"a;b;c" 或 "a\;b\;c\;" 会被分割为 {"a","b","c"};
			"1\2\3" 或 "1\2\3\;"  会被分割为 {"1","2","3"};
			"one" 或 "one\;" 会被分割为 "one";
			"a1\a2;b;c" 或 "a1\a2\;b\;c\;" 会被分割为 { {"a1","a2"}, {"b"}, {"c"} }.
		作为特例, 当 str 为空字符串或 nil 时, 本函数会直接返回 str; 但是, "\", ";", 和 "\;" 会被正常分割为 {{""}} (禁用 flatten 时) 或 "" (启用 flatten 时).
		请注意, 本模板不支持转义. 若输入中必须要包含以上四个分隔符之一, 请使用 HTML Character Entity (在萌娘百科可以使用 {{ce}} )转义.
	]]
	lum.parseArray = function ( str, flatten, anonymousStr )
		--mw.log ('parseArray: received data: '..table.concat( {tostring(str), tostring(flatten), tostring(anonymousStr)}, ', ') )
		local s = str or anonymousStr
		if lum.isEmpty ( s ) then return s end
		flatten = flatten or false
		s = mw.ustring.gsub ( mw.ustring.gsub ( mw.ustring.gsub ( s, '、', '\\' ) , ';', ';' ), '([^;])$', '%1;' )
		local out = {}    local c1 = 0    local singleLeaf = true
		for m1 in mw.ustring.gmatch ( s, '([^;]*);') do
			c1 = c1 + 1
			out[c1] = {}
			local c2 = 0
			for m2 in mw.ustring.gmatch ( mw.ustring.gsub ( m1, '([^\\])$', '%1\\' ), '([^\\]*)\\') do
				c2 = c2 + 1
				out[c1][c2] = m2
			end
			if not out[c1][1] then out[c1][1] = '' end
			singleLeaf = singleLeaf and ( c2 < 2 )
		end
		if flatten then
			if singleLeaf then
				for i = 1, #out do out[i] = out[i][1] end
			end
			if #out < 2 then out = out[1] end
		end
		return out
	end
	lum.parseArray = lum.epa( lum.parseArray, { 'str', 'flatten', 1 }, function ( a ) return type(a[1]) == 'table' end )
	lum.parseTable = lum.parseArray


	

	
-------- 未分类 Uncategorized --------

return lum