Modul:Vorlage:Str
Vorlagenprogrammierung | Diskussionen | Lua | Test | Unterseiten | |||
---|---|---|---|---|---|---|---|
Modul | Deutsch | English
|
Modul: | Dokumentation |
local Str = { suite = "Str",
serial = "2018-09-03",
item = 0 }
--[=[
{{Template:Str *********}}
]=]
function fixPattern( arg )
-- Diasable Lua pattern syntax.
-- Precondition:
-- string; to be escaped
-- Postcondition:
-- Returns string with escaped syntax elements.
return mw.ustring.gsub( arg, ".", { ["%"] = "%%";
["^"] = "%^";
["$"] = "%$";
["."] = "%.";
["("] = "%(";
[")"] = "%)";
["["] = "%[";
["]"] = "%]";
["?"] = "%?";
["*"] = "%*";
["+"] = "%+";
["-"] = "%-";
["\0"] = "%z"; } )
end -- fixPattern()
function Str.crop( args )
-- Remove the right-most {2} characters of a string {1}.
-- Precondition:
-- 1 = A string
-- 2 = A length; 1 if omitted
-- Postcondition:
-- Throws error if {2} < 0
-- Returns string; remaining starting characters, if any.
local r
if args[ 1 ] then
local n = tonumber( args[ 2 ] )
r = mw.ustring.len( args[ 1 ] )
if not n then
if args[ 2 ] then
n = r
else
n = 1
end
elseif n < 0 then
error( "{{Str crop||"
.. args[ 2 ] .. "<0}}", 0 )
end
if n >= r then
r = ""
else
if n == 0 then
r = args[ 1 ]
elseif n == r then
r = ""
else
r = mw.ustring.sub( args[ 1 ], 1, r - n )
end
end
else
r = ""
end
return r
end -- .crop()
function Str.cropleft( args )
-- Remove the left-most {2} characters of a string {1}.
-- Precondition:
-- 1 = A string
-- 2 = A length; 1 if omitted
-- Postcondition:
-- Throws error if {2} < 0
-- Returns string; remaining starting characters, if any.
local r
if args[ 1 ] then
local n = tonumber( args[ 2 ] )
r = mw.ustring.len( args[ 1 ] )
if not n then
if args[ 2 ] then
n = r
else
n = 1
end
elseif n < 0 then
error( "{{Str cropleft||"
.. args[ 2 ] .. "<0}}", 0 )
end
if n >= r then
r = ""
else
n = math.floor( n )
if n == 0 then
r = args[ 1 ]
elseif n == r then
r = ""
else
r = mw.ustring.sub( args[ 1 ], n + 1 )
end
end
end
return r or ""
end -- .cropleft()
function Str.find( args )
-- Position of first appearance of {2} in {1}.
-- Precondition:
-- 1 = A base_string
-- 2 = A sub_string
-- Postcondition:
-- Returns string; -1 if sub_string not found
-- Character position is 1 based
-- (not 0 based as usual in calculations).
local r
if args[ 1 ] and args[ 2 ] then
local k
r, k = mw.ustring.find( args[ 1 ], args[ 2 ], 1, true )
if not r then
r = -1
end
elseif args[ 1 ] then
r = 1
else
r = -1
end
return r
end -- .find()
function Str.ge_len( args )
-- Conditional answer depending on string {1} length wrt {2}.
-- Template:Str ≥ len
-- Precondition:
-- 1 = A string
-- 2 = A length
-- 3 = Data to return/render when "longer than or equally long".
-- 4 = Data to return/render when "shorter than".
-- Postcondition:
-- Throws error if {1} undefined or invalid.
-- Returns string; either {3} or {4}.
local r
if args[ 1 ] then
local n = tonumber( args[ 2 ] )
r = mw.ustring.len( args[ 1 ] )
if not n then
r = args[ 3 ] or ""
elseif r < n then
r = args[ 4 ] or ""
else
r = args[ 3 ] or ""
end
else
error( "{{Str ≥ len}}", 0 )
end
return r
end -- .ge_len()
function Str.hex2dez( args )
-- Returns the decimal value of an octethexcode {1}.
-- Precondition:
-- 1 = A hexcode (octets)
return tonumber( args[ 1 ], 16 ) or 0
end -- .hex2dez()
function Str.index( args )
-- Returns the {2}-th character of trimmed text {1}.
-- Precondition:
-- 1 = A string
-- 2 = A position, counted from 1 in string
-- Postcondition:
-- Throws error if {2} < 0 or {2} out of {1}
local r = tonumber( args[ 2 ] )
if r then
if r <= 0 then
error( "{{Str index||"
.. args[ 2 ] .. "<=0}}", 0 )
elseif args[ 1 ] then
local n = mw.ustring.len( args[ 1 ] )
if n < r then
error( "{{Str index||"
.. args[ 2 ] .. ">>}}", 0 )
else
r = mw.ustring.sub( args[ 1 ], r, r )
end
else
error( "{{Str index}}", 0 )
end
else
if args[ 2 ] then
r = args[ 2 ] .. "}}"
else
r = "}}"
end
error( "{{Str index||" .. r, 0 )
end
return r
end -- .index()
function Str.left( args )
-- Gives the {2}-length substring of characters
-- from the start of the trimmed string {1}.
-- Precondition:
-- 1 = A string
-- 2 = A length; if omitted, 1 is used
-- Postcondition:
-- Return the left {2} characters of {1}.
-- If {2} is invalid, empty or zero, an empty string is returned.
local n, r
if not args[ 2 ] then
n = 1
elseif args[ 2 ] == "" then
n = 0
else
n = tonumber( args[ 2 ] )
if not n then
n = 0
end
end
if n > 0 and args[ 1 ] then
r = mw.ustring.sub( args[ 1 ], 1, n )
else
r = ""
end
return r
end -- .left()
function Str.len( args )
-- Returns length of string (excluding spaces at the start and end).
-- Precondition:
-- 1 = A string
local r
if args[ 1 ] then
r = tostring( mw.ustring.len( args[ 1 ] ) )
else
r = "0"
end
return r
end -- .len()
function Str.match( args )
-- Get string {1} containing pattern {2}, optional in capture (3).
-- Precondition:
-- 1 = A string; whitespace around will be kept
-- 2 = A pattern; all (1) if invalid
-- 3 = An optional number; 0 if invalid, else sequenced capture
-- Postcondition:
-- Returns string.
local r = args[ 1 ]
local s = args[ 2 ]
if r and s then
local k = tonumber( args[ 3 ] )
if not k or k < 0 then
k = 0
else
k = math.floor( k )
end
r = ( { mw.ustring.match( r, s ) } )
if k > 0 then
r = r[ k ]
else
r = table.concat( r )
end
end
return r or ""
end -- .match()
function Str.repeating( args )
-- Repeat string {1} as often as {2} indicates.
-- Precondition:
-- 1 = A string; whitespace around will be kept
-- 2 = A factor; 1 if omitted or invalid
-- Postcondition:
-- Returns string.
local r = args[ 1 ]
if r then
local n = tonumber( args[ 2 ] )
if not n then
n = 1
end
if n > 1 then
r = r:rep( n )
end
else
r = ""
end
return r
end -- .repeating()
function Str.replace( args )
-- Replace in string {1} string {2} with string (3).
-- Precondition:
-- 1 = A string; whitespace around will be kept
-- 2 = A seek string; whitespace around will be kept
-- 3 = A replacing string; whitespace around will be kept
-- 4 = An optional number; limit number of replacements
-- 5 = An optional boolean; 0 or 1, regard seek as pattern
-- Postcondition:
-- Returns string.
local r = args[ 1 ]
local seek = args[ 2 ]
if r and seek then
local s = args[ 3 ] or ""
local n = tonumber( args[ 4 ] )
local l = args[ 5 ]
if not n or n < 1 then
n = nil
else
n = math.floor( n )
end
if l then
l = mw.text.trim( l )
if l ~= "" and l ~= "0" then
seek = fixPattern( seek )
s = mw.ustring.gsub( s, "%%", "%%%%")
end
end
r, l = mw.ustring.gsub( r, seek, s, n )
end
return r or ""
end -- .replace()
function Str.right( args )
-- Gives the characters from {2} to the end of the string {1}.
-- Precondition:
-- 1 = A string
-- 2 = An offset
-- A negative offset is treated the same as zero,
-- which simply returns the original string.
local r = args[ 1 ]
if r then
local n = tonumber( args[ 2 ] )
if n then
n = math.floor( n )
else
n = 0
end
if n > 0 then
r = mw.ustring.sub( r, n + 1 )
end
end
return r or ""
end -- .right()
function Str.rightc( args )
-- Gives the rightmost {1} characters from {2}.
-- Precondition:
-- 1 = A string
-- 2 = A count
-- A negative count is treated the same as zero,
-- which simply returns the original string.
local r
if r then
local n = tonumber( args[ 2 ] )
if n then
n = math.floor( n )
else
n = 0
end
if n > 0 then
r = mw.ustring.sub( r, - n )
end
end
return r or ""
end -- .rightc()
function Str.split( args )
-- Substring of string {2} split {1} time or at pattern {3}.
-- Precondition:
-- 1 = A count (<= 0: count, else number of)
-- 2 = A string
-- 3 = A pattern
-- 4 = An optional boolean; 0 or 1, take pattern literally
local r = args[ 2 ]
if r then
local n = tonumber( args[ 2 ] )
local s = args[ 3 ] or ""
local l = args[ 4 ]
local e
if n then
n = math.floor( n )
else
n = 0
end
if l then
l = ( l ~= "0" )
end
e = mw.text.split( r, s, l )
if n <= 0 then
r = #e
elseif n <= #r then
r = e[ n ]
end
end
return r or ""
end -- .split()
function Str.sub0( args )
-- Substring of string {1} starting at {2} and containing {3} chars.
-- en:Template:Str sub old
-- Precondition:
-- 1 = A string
-- 2 = An offset
-- Base 0: the first character is numbered 0, and so on.
-- 3 = A length
local r
local e = false
if args[ 1 ] then
local n = tonumber( args[ 3 ] )
if not n then
if args[ 3 ] then
e = "|||" .. args[ 3 ] .. "}}"
else
n = 0
end
end
if not e then
if n < 0 then
e = "|||" .. args[ 3 ] .. "<0}}"
else
local i = tonumber( args[ 2 ] )
if not i or i < 0 then
if args[ 2 ] then
e = "||" .. args[ 2 ] .. "}}"
else
e = "||}}"
end
elseif n == 0 then
r = ""
else
r = mw.ustring.sub( args[ 1 ], i + 1, i + n )
end
end
end
else
e = "}}"
end
if e then
error( "{{Str sub0" .. e, 0 )
end
return r
end -- .sub0()
function Str.sub1( args )
-- Substring of string {1} starting at {2} and containing {3} chars.
-- en:Template:Str sub new
-- Precondition:
-- 1 = A string
-- 2 = An offset
-- Base 1: the first character is numbered 1, and so on.
-- 3 = A length
local r
local e = false
if args[ 1 ] then
local n = tonumber( args[ 3 ] )
if not n then
if args[ 3 ] then
e = "|||" .. args[ 3 ] .. "}}"
else
n = 0
end
end
if not e then
if n < 0 then
e = "|||" .. args[ 3 ] .. "<0}}"
else
local i = tonumber( args[ 2 ] )
if not i or i < 1 then
if args[ 2 ] then
e = "||" .. args[ 2 ] .. "}}"
else
e = "||}}"
end
elseif n == 0 then
r = ""
else
r = mw.ustring.sub( args[ 1 ], i, i + n )
end
end
end
else
e = "}}"
end
if e then
error( "{{Str sub1" .. e, 0 )
end
return r
end -- .sub1()
function Str.failsafe( assert )
-- Retrieve versioning and check for compliance
-- Precondition:
-- assert -- string, with required version or false
-- Postcondition:
-- Returns string with appropriate version, or false
local since = assert
local r
if since == "wikidata" then
local item = Str.item
since = false
if type( item ) == "number" and item > 0 then
local ent = mw.wikibase.getEntity( string.format( "Q%d",
item ) )
if type( ent ) == "table" then
local vsn = ent: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 <= Str.serial then
r = Str.serial
else
r = false
end
end
return r
end -- Str.failsafe()
local function Facing( frame, action, leave )
-- Run actual code from template transclusion ot direct invocation
-- Precondition:
-- frame -- object
-- action -- string with function name
-- leave -- true: keep whitespace around
-- Postcondition:
-- Return string; like the legacy templates
-- might be error message
local got = frame.args
local lucky, r
if not pairs( got ) then
-- no #invoke parameters, try transclusion parameters
got = frame:getParent().args
end -- for k, v
if not leave then
for k, v in pairs( got ) do
got[ k ] = mw.text.trim( v )
end -- for k, v
end
lucky, r = pcall( Str[ action ], got )
if not lucky then
local e = mw.html.create( "span" )
r = tostring( e:addClass( "error" )
:wikitext( r ) )
end
return r
end -- Facing()
-- Export
local p = { }
function p.TEST( action, args )
-- Run main code from test environment
-- Precondition:
-- action -- string with function name
-- args -- table; simulated environment
-- Postcondition:
-- Return string; like the legacy templates
local lucky, r
for k, v in ipairs( args ) do
args[ k ] = mw.text.trim( v )
end -- for k, v
lucky, r = pcall( Str[ action ], args )
return r
end -- p.TEST()
p.crop = function ( frame )
return Facing( frame, "crop" )
end
p.cropleft = function ( frame )
return Facing( frame, "cropleft" )
end
p.find = function ( frame )
return Facing( frame, "find" )
end
p.hex2dez = function ( frame )
return Facing( frame, "hex2dez" )
end
p.index = function ( frame )
return Facing( frame, "index" )
end
p.left = function ( frame )
return Facing( frame, "left" )
end
p.len = function ( frame )
return Facing( frame, "len" )
end
p[ "≥ len" ] = function ( frame )
return Facing( frame, "ge_len" )
end
p.match = function ( frame )
return Facing( frame, "match", true )
end
p.repeating = function ( frame )
return Facing( frame, "repeating", true )
end
p.replace = function ( frame )
return Facing( frame, "replace", true )
end
p.right = function ( frame )
return Facing( frame, "right" )
end
p.rightc = function ( frame )
return Facing( frame, "rightc" )
end
p.split = function ( frame )
return Facing( frame, "split" )
end
p.sub = function ( frame )
return Facing( frame, "sub0" )
end
p.sub0 = function ( frame )
return Facing( frame, "sub0" )
end
p.sub_old = function ( frame )
return Facing( frame, "sub0" )
end
p.sub1 = function ( frame )
return Facing( frame, "sub1" )
end
p.sub_new = function ( frame )
return Facing( frame, "sub1" )
end
p.failsafe = function ( frame )
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 Str.failsafe( since ) or ""
end
p.Str = function ()
return Str
end
return p