Module:Loop
跳到导航
跳到搜索
简介
该模块可以循环执行语句。相较于解析器函数,因为使用Lua模块进行循环,所以没有100次上限的限制。
用法和功能与{{loop}}类似,但可以处理模板的接收参数(也即被三对大括号包裹的参数,如{{{1}}}
)
用法
注意:
- 第一层循环的代码需要用
<nowiki>
标签包裹。 - 多层循环中内层循环的代码不需要
<nowiki>
标签包裹。
- loop
{{#invoke:loop|main| 自增/减变量名 = 初始值 | 最大值 | 自增/减量 |do= <nowiki> 循环执行的代码... </nowiki>}}
main
亦可作loop
、for
。- 使用自增/减变量的写法为:
{{#var:变量名}}
,如:{{#var:time}}
。 - 默认的自增/减量在初始值小于最大值为1,在初始值大于最大值时为-1。
- while/dowhile
{{#invoke:loop|while| condition = <nowiki>循环条件</nowiki> |do= <nowiki> 循环执行的代码... </nowiki>}}
{{#invoke:loop|dowhile| condition = <nowiki>循环条件</nowiki> |do= <nowiki> 循环执行的代码... </nowiki>}}
- fornumargs
{{#invoke:loop|fornumargs| 变量名前缀 | 索引变量名 | 值变量名 |<nowiki> 循环执行的代码... </nowiki>}}
- 具体使用方法可参考Help:魔术字/解析器函数#循环中的相关介绍。
示例
示例1
{{#vardefine:count|0}}<!-- -->{{#invoke:loop|main|time=1|101|do= <nowiki>{{#vardefine:count| {{#expr: {{#var:count}} + {{#var:time}} }} }}</nowiki> }} 结果:{{#var:count}}
结果:5151
示例2
{{#vardefine:count|0}}<!-- -->{{#invoke:loop|main|time1=1|5|do=<nowiki> {{#invoke:loop|main|time2=1|100|do= {{#vardefine:count| {{#expr: {{#var:count}} + {{#var:time1}} * {{#var:time2}} }} }} }} </nowiki>}} 结果:{{#var:count}}
结果:75750
示例3
{{#invoke:loop|main|time=1|5 |do=<nowiki> {{#expr:{{#var:time}} + {{{1|0}}} }}{{{split|、}}} </nowiki> }}
1、2、3、4、5、
- 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