模块:Loop
来自东方活动维基
本页面原来自萌娘百科页面模块:Loop,依 CC BY-NC-SA 3.0 授权引入。 经过双方编者的修改,本页面可能已与来源有很大差异。 |
local module = {}
local getArgs = require('Module:Arguments').getArgs
local nowiki_blocks = { 'do', 'condition' }
function pack_inner_loop(loop)
-- 给内层循环的do参数包裹<nowiki>标签
loop = mw.ustring.gsub(loop, '{{%s-[Ll]oop%s-|', '{{#invoke:loop|loop|')
loop = mw.ustring.gsub(loop, '{{%s-[Ww]hile%s-|', '{{#invoke:loop|while|')
loop = mw.ustring.gsub(loop, '{{%s-[Dd]o[Ww]hile%s-|', '{{#invoke:loop|dowhile|')
return mw.ustring.gsub(loop, '({{#invoke:loop.*)', function(a)
local i = 1
local stack = {}
local block_begin = -1
local block_end = -1
while (i < mw.ustring.len(a)) do
for _, block in ipairs(nowiki_blocks) do
if block_begin == -1 and mw.ustring.find(a, '^|%s-'..block..'%s-=', i) then
_, block_begin = mw.ustring.find(a, '^|%s-'..block..'%s-=', i)
block_begin = block_begin + 1
i = block_begin
break
end
end
if block_begin ~= -1 then
if mw.ustring.sub(a, i, i + 2) == '{{{' then
i = i + 3
table.insert(stack, 3)
elseif mw.ustring.sub(a, i, i + 1) == '{{' then
i = i + 2
table.insert(stack, 2)
elseif mw.ustring.sub(a, i, i + 2) == '}}}' then
if #stack ~= 0 and stack[#stack] == 3 then
i = i + 3
table.remove(stack)
elseif #stack ~= 0 and stack[#stack] == 2 then
i = i + 2
table.remove(stack)
else
block_end = i - 1
break
end
elseif mw.ustring.sub(a, i, i + 1) == '}}' then
if #stack ~= 0 then
i = i + 2
table.remove(stack)
else
block_end = i - 1
break
end
elseif mw.ustring.sub(a, i, i) == '|' and #stack == 0 then
block_end = i - 1
break
else
i = i + 1
end
else
i = i + 1
end
end
if block_begin ~= -1 and block_end == -1 then block_end = i - 1 end
if block_begin ~= -1 and block_end ~= -1 then
-- mw.log('发现内层循环 <nowiki>'..mw.ustring.sub(a, block_begin, block_end)..'</nowiki>')
return mw.ustring.sub(a, 1, block_begin - 1)..'<nowiki>'..
mw.text.trim(mw.ustring.sub(a, block_begin, block_end))..'</nowiki>'..
pack_inner_loop(mw.ustring.sub(a, block_end + 1, -1))
else
return a
end
end )
end
function _loop(args, frame)
local name = ''
local _min = 1
local _max = tonumber(args['max'] or args[1] or 10)
local addend = tonumber(args[2] or 1)
local loop = args['do'] or ''
loop = mw.text.unstripNoWiki(loop)
loop = string.gsub(loop, '<!%-%-.-%-%->', '')
loop = pack_inner_loop(loop)
local trim = mw.text.split(loop, '\n')
loop = ''
for i, v in ipairs(trim) do
loop = loop..mw.text.trim(v)
end
for k, v in pairs(args) do
if(k ~= 'do' and k ~= 'max' and k ~= 1 and k ~= 2) then
name = string.gsub(k, '([%%%(%)%.%+%-%*%?%[%]%^%$])', '%%%1')
_min = tonumber(v)
break
end
end
if name == '' then error('必须设置自增/自减的变量名!') end
loop = mw.text.decode(loop)
-- mw.log('循环体= '..loop)
local result = ''
if type(args[2]) == 'nil' and _min > _max and addend > 0 then addend = -1 end
for i=_min, _max, addend do
frame:callParserFunction('#vardefine', name, i)
-- mw.log('执行循环体('..name..'='..tostring(i)..') '..loop)
result = result..frame:preprocess(loop)
end
-- mw.log('循环结果 '..result)
return result
end
function module.loop(frame)
if (frame:getParent() or frame):getTitle() == 'Template:Loop' and
frame.args['do'] == nil then
args = getArgs(frame)
else
args = frame.args
end
return _loop(args, frame:getParent() or frame)
end
-- 向后兼容
function module.main(frame)
return module.loop(frame)
end
-- 别名
module["for"] = function(frame)
return module.loop(frame)
end
local _while = function(args, frame, dowhile)
--初步处理条件语句
local condition = args['condition'] or ''
condition = mw.text.unstripNoWiki(condition)
condition = string.gsub(condition, '<!%-%-.-%-%->', '')
--修整条件语句的格式
local trim = mw.text.split(condition, '\n')
condition = ''
for i, v in ipairs(trim) do
condition = condition..mw.text.trim(v)
end
condition = mw.text.decode(condition)
-- mw.log('循环体= '..condition)
--初步处理循环体
local loop = args['do'] or ''
loop = mw.text.unstripNoWiki(loop)
loop = string.gsub(loop, '<!%-%-.-%-%->', '')
--处理循环体中的次级循环语句
loop = pack_inner_loop(loop)
--修整循环体中语句的格式
local trim = mw.text.split(loop, '\n')
loop = ''
for i, v in ipairs(trim) do
loop = loop..mw.text.trim(v)
end
loop = mw.text.decode(loop)
-- mw.log('循环体= '..loop)
local result = ''
if dowhile then
-- mw.log('执行循环体('..name..'='..tostring(i)..') '..loop)
repeat result = result..frame:preprocess(loop) until frame:preprocess(condition) == ''
else
-- mw.log('执行循环体('..name..'='..tostring(i)..') '..loop)
while frame:preprocess(condition) ~= '' do result = result..frame:preprocess(loop) end
end
-- mw.log('循环结果 '..result)
return result
end
module["while"] = function(frame)
if (frame:getParent() or frame):getTitle() == 'Template:While' and
frame.args['do'] == nil then
args = getArgs(frame)
else
args = frame.args
end
return _while(args, frame:getParent() or frame, false)
end
module.dowhile = function(frame)
if (frame:getParent() or frame):getTitle() == 'Template:While' and
frame.args['do'] == nil then
args = getArgs(frame)
else
args = frame.args
end
return _while(args, frame:getParent() or frame, true)
end
function module.fornumargs(frame)
local args = frame.args
local parent = frame:getParent()
local prefix = mw.text.trim(args[1] or '')
local numname = mw.text.trim(args[2] or '')
local valname = mw.text.trim(args[3] or '')
local cond = mw.text.decode(mw.text.unstripNoWiki(mw.text.trim(args.cond or '')))
local text = mw.text.decode(mw.text.unstripNoWiki(mw.text.trim(args[4] or '')))
if not parent or numname == '' or valname == '' or text == '' then return '' end
local expr = '^' .. mw.ustring.gsub(prefix, '([-+*?%%])', '%%%1') .. '(%d+)$'
local keys = {}
local output = {}
for key, _ in pairs(parent.args) do
local num = mw.ustring.match(key, expr)
if num then
table.insert(keys, tonumber(num))
end
end
table.sort(keys)
for _, idx in ipairs(keys) do
parent:callParserFunction('#vardefine', numname, idx)
parent:callParserFunction('#vardefine', valname, parent.args[prefix .. idx])
if cond == '' or parent:preprocess(cond) ~= '' then
table.insert(output, parent:preprocess(text))
end
end
return table.concat(output)
end
return module