Modul:Sort
Die Dokumentation für dieses Modul kann unter Modul:Sort/Doku erstellt werden
local Sort = { suite = "Sort",
serial = "2018-03-22",
item = 24205172 }
--[=[
Sort
]=]
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 storage = string.format( "Module:%s/", Sort.suite )
local collate, lucky, post, pre
if apply then
collate = apply
else
collate = "uni"
end
if type( collate ) == "string" then
lucky, collate = pcall( mw.loadData, storage .. collate )
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
lucky, tmp = pcall( mw.loadData,
storage .. variants[ i ] )
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 lucky then
collate = "Invalid table " .. variants[ i ]
break -- for i
else
collate = tmp
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 >= 768 and k <= 866) or
(k >= 6832 and k <= 6911) or
(k >= 7616 and k <= 7679) or
(k >= 65056 and k <= 65071) 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()
Sort.failsafe = function ( assert )
-- Retrieve versioning and check for compliance
-- Precondition:
-- assert -- string, with required version or "wikidata",
-- or false
-- Postcondition:
-- Returns string with appropriate version, or false
local since = assert
local r
if since == "wikidata" then
local item = Sort.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 vsn = entity:formatPropertyValues( "P348" )
if type( vsn ) == "table" and
type( vsn.value) == "string" and
vsn.value ~= "" then
r = vsn.value
end
end
end
end
if not r then
if not since or since <= Sort.serial then
r = Sort.serial
else
r = false
end
end
return r
end -- Sort.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 Sort.failsafe( since ) or ""
end -- p.failsafe()
p.Sort = function ()
return Sort
end -- p.Sort
return p