Zum Inhalt springen

Modul:Sort

Aus Wikipedia
Vorlagenprogrammierung Diskussionen Lua Test Unterseiten
Modul Deutsch English

Modul: Dokumentation

Diese Seite enthält Code in der Programmiersprache Lua. Einbindungszahl Cirrus

Weiterleitung der Diskussionsseite fehlt
Diese Seite ist eine lokale Kopie aus de.wikipedia.org und von dort zu aktualisieren.

Versionsbezeichnung auf WikiData: 2024-06-14 Updating notwendig (lokal: 2019-10-29)


local Sort = { suite  = "Sort",
               serial = "2019-10-29",
               item   = 24205172 }
--[=[
Sort
]=]
local Failsafe  = Sort
local GlobalMod = Sort



local foreignModule = function ( access, advanced, append, alt, alert )
    -- Fetch global module
    -- Precondition:
    --     access    -- string, with name of base module
    --     advanced  -- true, for require(); else mw.loadData()
    --     append    -- string, with subpage part, if any; or false
    --     alt       -- number, of wikidata item of root; or false
    --     alert     -- true, for throwing error on data problem
    -- Postcondition:
    --     Returns whatever, probably table
    -- 2019-10-29
    local storage = access
    local finer = function ()
                      if append then
                          storage = string.format( "%s/%s",
                                                   storage,
                                                   append )
                      end
                  end
    local fun, lucky, r, suited
    if advanced then
        fun = require
    else
        fun = mw.loadData
    end
    GlobalMod.globalModules = GlobalMod.globalModules or { }
    suited = GlobalMod.globalModules[ access ]
    if not suited then
        finer()
        lucky, r = pcall( fun,  "Module:" .. storage )
    end
    if not lucky then
        if not suited  and
           type( alt ) == "number"  and
           alt > 0 then
            suited = string.format( "Q%d", alt )
            suited = mw.wikibase.getSitelink( suited )
            GlobalMod.globalModules[ access ] = suited or true
        end
        if type( suited ) == "string" then
            storage = suited
            finer()
            lucky, r = pcall( fun, storage )
        end
        if not lucky and alert then
            error( "Missing or invalid page: " .. storage, 0 )
        end
    end
    return r
end -- foreignModule()



Sort.lex = function ( adjust, apply, adapt )
    -- Build ASCII sortkey for text value
    -- Precondition:
    --     adjust  -- string to be aligned
    --     apply   -- string or table, with base
    --                "latin"
    --     adapt   -- string or table, with variation, or false
    --                "DIN5007m2"  -- DIN 5007 mode "2"
    local r = adjust
    if adapt  or  not r:match( "^[ -~]*$" ) then
        local collate, post, pre
        if apply then
            collate = apply
        else
            collate = "uni"
        end
        if type( collate ) == "string" then
            collate = foreignModule( Sort.suite,
                                     false,
                                     collate,
                                     Sort.item )
        end
        if adapt  and  type( collate ) == "table" then
            local variants = type( adapt )
            local n
            if variants == "string" then
                variants = mw.text.split( adapt, "%s+" )
            elseif variants == "table" then
                variants = adapt
            else
                variants = { }
            end
            n = #variants
            if n == 1  and  variants[ 1 ] == "" then
                n = 0
            end
            if n > 0 then
                local tmp = { }
                local var
                for k, v in pairs( collate ) do
                    tmp[ k ] = v
                end    -- for k, v
                collate = tmp
                for i = 1, n do
                    tmp = foreignModule( Sort.suite,
                                         false,
                                         variants[ i ],
                                         Sort.item )
                    if type( tmp ) == "table" then
                        var = tmp.single
                        if type( var ) ~= "table" then
                            -- legacy
                            var = tmp
                        end
                        if type( var ) == "table" then
                            for k, v in pairs( var ) do
                                collate[ k ] = v
                            end    -- for k, v
                        end
                        var = tmp.pre
                        if type( var ) == "table" then
                            if type( pre ) ~= "table" then
                                pre = { }
                            end
                            for k, v in pairs( var ) do
                                pre[ k ] = v
                            end    -- for k, v
                        end
                        var = tmp.post
                        if type( var ) == "table" then
                            if type( post ) ~= "table" then
                                post = { }
                            end
                            for k, v in pairs( var ) do
                                post[ k ] = v
                            end    -- for k, v
                        end
                    elseif type( tmp ) == "string" then
                        collate = tmp
                        break    -- for i
                    else
                        collate = "Invalid table " .. variants[ i ]
                        break    -- for i
                    end
                end    -- for i
            end
        end
        if type( collate ) == "table" then
            local k, n, s, start
            if type( pre ) == "table" then
                for k, v in pairs( pre ) do
                    r = mw.ustring.gsub( r, k, v )
                end    -- for k, v
            end
            n = mw.ustring.len( r )
            for i = n, 1, -1 do
                k = mw.ustring.codepoint( r, i, i )
                if k < 127 then    -- ASCII
                    s = ( k < 32 )    -- htab newline whitespace
                    if s then
                        s = " "
                    end
                elseif ( k >= 0x0300  and  k <= 0x0362 )   or
                       ( k >= 0x1AB0  and  k <= 0x1AFF )   or
                       ( k >= 0x1DC0  and  k <= 0x1DFF )   or
                       ( k >= 0xFE20  and  k <= 0xFE2F ) then
                    -- COMBINING ...
                    s = ""
                else
                    s = collate[ k ]
                end
                if s then
                    if i > 1 then
                        s = mw.ustring.sub( r, 1,  i - 1 )  ..  s
                    end
                    r = s .. mw.ustring.sub( r,  i + 1 )
                end
            end    -- for i--
            if type( post ) == "table" then
                for k, v in pairs( post ) do
                    r = mw.ustring.gsub( r, k, v )
                end    -- for k, v
            end
        else
            r = "**ERROR** Sort.lex ** Submodule unavailable " .. collate
        end
    end
    r = r:gsub( "  +", " " )
    return r
end -- Sort.lex()



Sort.num = function ( adjust, ad, at, align, absolute )
    -- Build sortkey for heading numerical value
    -- Precondition:
    --     adjust    -- string to be aligned; leading digits / minus
    --     ad        -- decimal separator; "." or ","; defaults to "."
    --     at        -- thousands group separator; defaults to none
    --                  ","  "."  "'"
    --     align     -- number of leading zeros / maximum length
    --                  defaults to 15
    --     absolute  -- negative figures by digits; default: by value
    -- Postcondition:
    --     Returns string with sortkey
    local max    = 15
    local mid    = 46    -- "."
    local min1   = -1    -- none
    local min2   = -2    -- none
    local low    = false
    local last   = false
    local lead   = true
    local source = tostring( adjust )
    local sub    = "."
    local suffix = false
    local n      = mw.ustring.len( source )
    local r      = ""
    local c
    if ad then
        mid = mw.ustring.codepoint( ad, 1, 1 )
    end
    if at then
        min1, min2 = mw.ustring.codepoint( at, 1, 2 )
    end
    if align then
        max = align
    end
    for i = 1, n do
        c = mw.ustring.codepoint( source, i, i )
        if c > 32 then    -- not whitespace
            if c >= 48 and c <= 57 then    -- digits
                r   = string.format( "%s%c", r, c )
                max = max - 1
            elseif c == min1 or c == min2 then    -- group separator
            elseif c == mid then    -- decimal separator
                 for j = i + 1, n do
                     c = mw.ustring.codepoint( source, j, j )
                     if c >= 48 and c <= 57 then    -- digits
                         sub = string.format( "%s%c", sub, c )
                     elseif c == min1 or c == min2 then    -- grouping
                     else
                         i = j
                         break    -- for j
                     end
                     i = n
                 end    -- for j
                 last = true
            elseif lead then
                if c == 45 or c == 8722 then    -- minus
                    low = true
                elseif c ~= 43 then    -- plus
                    last = true
                end
            else
                last = true
            end
            lead = false
        elseif not lead then    -- whitespace not leading
            last = true
        end
        if last then
            if i < n then
                suffix = mw.ustring.sub( source, i )
                if c == 69  or  c == 101 then    -- E e
                    local s = suffix:match( "^[Ee](-?%d+)" )
                    if s then
                        j      = tonumber( s )
                        sub    = sub:sub( 2 )
                        suffix = suffix:sub( #s + 2 )
                        if j > 0 then
                            if j > #sub then
                                sub = sub .. string.rep( "0",  j - #sub )
                            end
                            r   = r .. sub:sub( 1, j )
                            sub = sub:sub( j + 1 )
                            max = max - j
                        elseif j < 0 then
                            j = - j
                            if j > #r then
                                r = string.rep( "0",  j - #r ) .. r
                            end
                            sub = r:sub( - j ) .. sub
                            r   = r:sub( 1,  #r - j )
                            max = max + j
                        end
                        sub = "." .. sub
                    end
                end
            end
            break    -- for i
       end
    end    -- for i
    if low then
        if not absolute then   -- complementary value
            local s    = "."
            local cmpl = function ( str, k )
                             return 57 - str:byte( k )
                         end
            for i = 2, #sub do
                s = string.format( "%s%d",  s,  cmpl( sub, i ) )
            end    -- for i
            for i = #r, 1, -1 do
                s = string.format( "%d%s",  cmpl( r, i ),  s )
            end    -- for i--
            r = s
            if max > 0 then
                r = string.rep( "9", max )  ..  r
            end
            sub = false
            max = 0
        end
    end
    if sub then
        r = r .. sub
    end
    if max > 0 then
        r = string.rep( "0", max )  ..  r
    end
    if low then
        r = "-" .. r
    end
    if suffix then
        r = string.format( "%s %s", r, suffix )
    end
    return r
end -- Sort.num()



Failsafe.failsafe = function ( atleast )
    -- Retrieve versioning and check for compliance
    -- Precondition:
    --     atleast  -- string, with required version or "wikidata" or "~"
    --                 or false
    -- Postcondition:
    --     Returns  string  -- with queried version, also if problem
    --              false   -- if appropriate
    -- 2019-10-15
    local last  = ( atleast == "~" )
    local since = atleast
    local r
    if last  or  since == "wikidata" then
        local item = Failsafe.item
        since = false
        if type( item ) == "number"  and  item > 0 then
            local entity = mw.wikibase.getEntity( string.format( "Q%d",
                                                                 item ) )
            if type( entity ) == "table" then
                local seek = Failsafe.serialProperty or "P348"
                local vsn  = entity:formatPropertyValues( seek )
                if type( vsn ) == "table"  and
                   type( vsn.value ) == "string"  and
                   vsn.value ~= "" then
                    if last  and  vsn.value == Failsafe.serial then
                        r = false
                    else
                        r = vsn.value
                    end
                end
            end
        end
    end
    if type( r ) == "nil" then
        if not since  or  since <= Failsafe.serial then
            r = Failsafe.serial
        else
            r = false
        end
    end
    return r
end -- Failsafe.failsafe()



-- Export
local p = { }

p.Tlatin = function ( frame )
    -- Template::latin
    --     {{{1}}}
    -- #invoke
    --     v  -- variant, omitted or "DIN5007m2"
    local lucky, r = pcall( Sort.lex,
                            frame.args[ 1 ]  or
                            frame:getParent().args[ 1 ]  or
                            "",
                            "latin",
                            frame.args.v )
    return r;
end -- p.Tlatin



p.Tn = function ( frame )
    -- Template::numerical
    --     {{{1}}}
    -- #invoke
    --     d  -- decimal separator; defaults to "."
    --     t  -- thousands group separator; defaults to none
    --     z  -- number of leading zeros / maximum length; defaults to 15
    --     m  -- negative figures by digits; default: by value
    local lucky, r = pcall( Sort.num,
                            frame.args[ 1 ]  or
                            frame:getParent().args[ 1 ]  or
                            "",
                            frame.args.d,
                            frame.args.t,
                            tonumber( frame.args.z ),
                            frame.args.m == "1" )
    return r;
end -- p.Tn



p.failsafe = function ( frame )
    -- Versioning interface
    local s = type( frame )
    local since
    if s == "table" then
        since = frame.args[ 1 ]
    elseif s == "string" then
        since = frame
    end
    if since then
        since = mw.text.trim( since )
        if since == "" then
            since = false
        end
    end
    return Failsafe.failsafe( since )  or  ""
end -- p.failsafe()



p.Sort = function ()
    return Sort
end -- p.Sort

return p