模块:Loop

    来自中国珂学院

    可在模块:Loop/doc创建此模块的帮助文档

    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