H萌娘衷心希望身在疫区的编辑和读者保重身体。愿世界新型冠状病毒肺炎疫情早日结束!

模块:Loop

From H萌娘
Jump to: navigation, search

简介

该模块可以循环执行语句。相较于解析器函数,因为使用Lua模块进行循环,所以没有100次上限的限制

用法和功能与{{loop}}类似,但可以处理模板的接收参数(也即被三对大括号包裹的参数,如{{{1}}}

用法

{{#invoke:loop|main| 自增/减变量名 = 初始值 | 最大值 | 自增/减量 |do= <nowiki>
循环执行的代码...
</nowiki>}}

其中,使用自增/减变量的写法为:{{#var:变量名}},如:{{#var:time}}

默认的自增/减量在初始值小于最大值为1,在初始值大于最大值时为-1。

注意:

  • 第一层循环的代码需要用<nowiki>标签包裹
  • 多层循环中内层循环的代码不需要<nowiki>标签包裹

示例

示例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

function pack_inner_loop(loop)
    -- 给内层循环的do参数包裹<nowiki>标签
    loop = mw.ustring.gsub(loop, '{{%s-[lL][oO][oO][pP]%s-|', '{{#invoke:loop|main|')
    return mw.ustring.gsub(loop, '({{#invoke:loop.*)', function(a)
        local i = 1
        local stack = {}
        local do_begin = -1
        local do_end = -1
        while (i < mw.ustring.len(a)) do
            if do_begin == -1 and mw.ustring.find(a, '^|%s-do%s-=', i) then
                _, do_begin = mw.ustring.find(a, '^|%s-do%s-=', i)
                do_begin = do_begin + 1
                i = do_begin
            end
            if do_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
                        do_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
                        do_end = i - 1
                        break
                    end
                elseif mw.ustring.sub(a, i, i) == '|' and #stack == 0 then
                    do_end = i - 1
                    break
                else
                    i = i + 1
                end
            else
                i = i + 1
            end
        end
        if do_begin ~= -1 and do_end == -1 then do_end = i - 1 end
        if do_begin ~= -1 and do_end ~= -1 then
        -- mw.log('发现内层循环 <nowiki>'..mw.ustring.sub(a, do_begin, do_end)..'</nowiki>')
        return mw.ustring.sub(a, 1, do_begin - 1)..'<nowiki>'..
               mw.text.trim(mw.ustring.sub(a, do_begin, do_end))..'</nowiki>'..
               pack_inner_loop(mw.ustring.sub(a, do_end + 1, -1))
        else
            return a
        end
    end )
end

function _main(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.main(frame)
    if (frame:getParent() or frame):getTitle() == 'Template:Loop' and
        frame.args['do'] == nil then
        args = getArgs(frame)
    else
        args = frame.args
    end
    return _main(args, frame:getParent() or frame)
end

return module