2023年政策修订增补工作正在进行中,欢迎参与!
Module:Sandbox/公的驱逐舰/LUM
跳转到导航
跳转到搜索
--[[
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