モジュール:Loop
このモジュールについての説明文ページを モジュール:Loop/doc に作成できます
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