dewiki>PerfektesChaos (2019-10-29) |
K (1 Version importiert) |
Aktuelle Version vom 10. September 2023, 13:57 Uhr
Die Dokumentation für dieses Modul kann unter Modul:Sort/Doku erstellt werden
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