Changes

2,561 bytes added ,  09:45, 6 May 2021
m
1 revision imported
Line 42: Line 42:  
]]
 
]]
 
function str.len( frame )
 
function str.len( frame )
local new_args = str._getParameters( frame.args, {'s'} );
+
local new_args = str._getParameters( frame.args, {'s'} )
local s = new_args['s'] or '';
+
local s = new_args['s'] or ''
 
return mw.ustring.len( s )
 
return mw.ustring.len( s )
 
end
 
end
Line 71: Line 71:  
]]
 
]]
 
function str.sub( frame )
 
function str.sub( frame )
local new_args = str._getParameters( frame.args, { 's', 'i', 'j' } );
+
local new_args = str._getParameters( frame.args, { 's', 'i', 'j' } )
local s = new_args['s'] or '';
+
local s = new_args['s'] or ''
local i = tonumber( new_args['i'] ) or 1;
+
local i = tonumber( new_args['i'] ) or 1
local j = tonumber( new_args['j'] ) or -1;
+
local j = tonumber( new_args['j'] ) or -1
   −
local len = mw.ustring.len( s );
+
local len = mw.ustring.len( s )
    
-- Convert negatives for range checking
 
-- Convert negatives for range checking
 
if i < 0 then
 
if i < 0 then
i = len + i + 1;
+
i = len + i + 1
 
end
 
end
 
if j < 0 then
 
if j < 0 then
j = len + j + 1;
+
j = len + j + 1
 
end
 
end
    
if i > len or j > len or i < 1 or j < 1 then
 
if i > len or j > len or i < 1 or j < 1 then
return str._error( 'String subset index out of range' );
+
return str._error( 'String subset index out of range' )
 
end
 
end
 
if j < i then
 
if j < i then
return str._error( 'String subset indices out of order' );
+
return str._error( 'String subset indices out of order' )
 
end
 
end
   Line 107: Line 107:     
--[[
 
--[[
match
+
_match
    
This function returns a substring from the source string that matches a
 
This function returns a substring from the source string that matches a
specified pattern.
+
specified pattern. It is exported for use in other modules
    
Usage:
 
Usage:
{{#invoke:String|match|source_string|pattern_string|start_index|match_number|plain_flag|nomatch}}
+
strmatch = require("Module:String")._match
OR
+
sresult = strmatch( s, pattern, start, match, plain, nomatch )
{{#invoke:String|pos|s=source_string|pattern=pattern_string|start=start_index
  −
    |match=match_number|plain=plain_flag|nomatch=nomatch_output}}
      
Parameters
 
Parameters
Line 131: Line 129:  
         text.  Defaults to false.
 
         text.  Defaults to false.
 
     nomatch: If no match is found, output the "nomatch" value rather than an error.
 
     nomatch: If no match is found, output the "nomatch" value rather than an error.
  −
If invoked using named parameters, Mediawiki will automatically remove any leading or
  −
trailing whitespace from each string.  In some circumstances this is desirable, in
  −
other cases one may want to preserve the whitespace.
  −
  −
If the match_number or start_index are out of range for the string being queried, then
  −
this function generates an error.  An error is also generated if no match is found.
  −
If one adds the parameter ignore_errors=true, then the error will be suppressed and
  −
an empty string will be returned on any failure.
      
For information on constructing Lua patterns, a form of [regular expression], see:
 
For information on constructing Lua patterns, a form of [regular expression], see:
   −
* https://www.lua.org/manual/5.1/manual.html#5.4.1
+
* http://www.lua.org/manual/5.1/manual.html#5.4.1
* https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns
+
* http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns
* https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Ustring_patterns
+
* http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Ustring_patterns
    
]]
 
]]
 
-- This sub-routine is exported for use in other modules
 
-- This sub-routine is exported for use in other modules
function str._match( s, pattern, start, match_index, plain, nomatch )
+
function str._match( s, pattern, start, match_index, plain_flag, nomatch )
 
if s == '' then
 
if s == '' then
return str._error( 'Target string is empty' );
+
return str._error( 'Target string is empty' )
 
end
 
end
 
if pattern == '' then
 
if pattern == '' then
return str._error( 'Pattern string is empty' );
+
return str._error( 'Pattern string is empty' )
 
end
 
end
 
start = tonumber(start) or 1
 
start = tonumber(start) or 1
 
if math.abs(start) < 1 or math.abs(start) > mw.ustring.len( s ) then
 
if math.abs(start) < 1 or math.abs(start) > mw.ustring.len( s ) then
return str._error( 'Requested start is out of range' );
+
return str._error( 'Requested start is out of range' )
 
end
 
end
 
if match_index == 0 then
 
if match_index == 0 then
return str._error( 'Match index is out of range' );
+
return str._error( 'Match index is out of range' )
 
end
 
end
 
if plain_flag then
 
if plain_flag then
pattern = str._escapePattern( pattern );
+
pattern = str._escapePattern( pattern )
 
end
 
end
   Line 173: Line 162:  
else
 
else
 
if start > 1 then
 
if start > 1 then
s = mw.ustring.sub( s, start );
+
s = mw.ustring.sub( s, start )
 
end
 
end
   −
local iterator = mw.ustring.gmatch(s, pattern);
+
local iterator = mw.ustring.gmatch(s, pattern)
 
if match_index > 0 then
 
if match_index > 0 then
 
-- Forward search
 
-- Forward search
 
for w in iterator do
 
for w in iterator do
match_index = match_index - 1;
+
match_index = match_index - 1
 
if match_index == 0 then
 
if match_index == 0 then
result = w;
+
result = w
break;
+
break
 
end
 
end
 
end
 
end
 
else
 
else
 
-- Reverse search
 
-- Reverse search
local result_table = {};
+
local result_table = {}
local count = 1;
+
local count = 1
 
for w in iterator do
 
for w in iterator do
result_table[count] = w;
+
result_table[count] = w
count = count + 1;
+
count = count + 1
 
end
 
end
   −
result = result_table[ count + match_index ];
+
result = result_table[ count + match_index ]
 
end
 
end
 
end
 
end
Line 201: Line 190:  
if result == nil then
 
if result == nil then
 
if nomatch == nil then
 
if nomatch == nil then
return str._error( 'Match not found' );
+
return str._error( 'Match not found' )
 
else
 
else
return nomatch;
+
return nomatch
 
end
 
end
 
else
 
else
return result;
+
return result
 
end
 
end
 
end
 
end
 +
 +
--[[
 +
match
 +
 +
This function returns a substring from the source string that matches a
 +
specified pattern.
 +
 +
Usage:
 +
{{#invoke:String|match|source_string|pattern_string|start_index|match_number|plain_flag|nomatch_output}}
 +
OR
 +
{{#invoke:String|match|s=source_string|pattern=pattern_string|start=start_index
 +
    |match=match_number|plain=plain_flag|nomatch=nomatch_output}}
 +
 +
Parameters
 +
    s: The string to search
 +
    pattern: The pattern or string to find within the string
 +
    start: The index within the source string to start the search.  The first
 +
        character of the string has index 1.  Defaults to 1.
 +
    match: In some cases it may be possible to make multiple matches on a single
 +
        string.  This specifies which match to return, where the first match is
 +
        match= 1.  If a negative number is specified then a match is returned
 +
        counting from the last match.  Hence match = -1 is the same as requesting
 +
        the last match.  Defaults to 1.
 +
    plain: A flag indicating that the pattern should be understood as plain
 +
        text.  Defaults to false.
 +
    nomatch: If no match is found, output the "nomatch" value rather than an error.
 +
 +
If invoked using named parameters, Mediawiki will automatically remove any leading or
 +
trailing whitespace from each string.  In some circumstances this is desirable, in
 +
other cases one may want to preserve the whitespace.
 +
 +
If the match_number or start_index are out of range for the string being queried, then
 +
this function generates an error.  An error is also generated if no match is found.
 +
If one adds the parameter ignore_errors=true, then the error will be suppressed and
 +
an empty string will be returned on any failure.
 +
 +
For information on constructing Lua patterns, a form of [regular expression], see:
 +
 +
* http://www.lua.org/manual/5.1/manual.html#5.4.1
 +
* http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns
 +
* http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Ustring_patterns
 +
 +
]]
 
-- This is the entry point for #invoke:String|match
 
-- This is the entry point for #invoke:String|match
 
function str.match( frame )
 
function str.match( frame )
local new_args = str._getParameters( frame.args, {'s', 'pattern', 'start', 'match', 'plain', 'nomatch'} );
+
local new_args = str._getParameters( frame.args, {'s', 'pattern', 'start', 'match', 'plain', 'nomatch'} )
local s = new_args['s'] or '';
+
local s = new_args['s'] or ''
local start = tonumber( new_args['start'] ) or 1;
+
local start = tonumber( new_args['start'] ) or 1
local plain_flag = str._getBoolean( new_args['plain'] or false );
+
local plain_flag = str._getBoolean( new_args['plain'] or false )
local pattern = new_args['pattern'] or '';
+
local pattern = new_args['pattern'] or ''
local match_index = math.floor( tonumber(new_args['match']) or 1 );
+
local match_index = math.floor( tonumber(new_args['match']) or 1 )
local nomatch = new_args['nomatch'];
+
local nomatch = new_args['nomatch']
   −
return str._match( s, pattern, start, match_index, plain, nomatch )
+
return str._match( s, pattern, start, match_index, plain_flag, nomatch )
 
end
 
end
   Line 248: Line 280:  
]]
 
]]
 
function str.pos( frame )
 
function str.pos( frame )
local new_args = str._getParameters( frame.args, {'target', 'pos'} );
+
local new_args = str._getParameters( frame.args, {'target', 'pos'} )
local target_str = new_args['target'] or '';
+
local target_str = new_args['target'] or ''
local pos = tonumber( new_args['pos'] ) or 0;
+
local pos = tonumber( new_args['pos'] ) or 0
    
if pos == 0 or math.abs(pos) > mw.ustring.len( target_str ) then
 
if pos == 0 or math.abs(pos) > mw.ustring.len( target_str ) then
return str._error( 'String index out of range' );
+
return str._error( 'String index out of range' )
 
end
 
end
   −
return mw.ustring.sub( target_str, pos, pos );
+
return mw.ustring.sub( target_str, pos, pos )
 
end
 
end
   Line 274: Line 306:  
]]
 
]]
 
function str.str_find( frame )
 
function str.str_find( frame )
local new_args = str._getParameters( frame.args, {'source', 'target'} );
+
local new_args = str._getParameters( frame.args, {'source', 'target'} )
local source_str = new_args['source'] or '';
+
local source_str = new_args['source'] or ''
local target_str = new_args['target'] or '';
+
local target_str = new_args['target'] or ''
    
if target_str == '' then
 
if target_str == '' then
return 1;
+
return 1
 
end
 
end
   Line 320: Line 352:  
]]
 
]]
 
function str.find( frame )
 
function str.find( frame )
local new_args = str._getParameters( frame.args, {'source', 'target', 'start', 'plain' } );
+
local new_args = str._getParameters( frame.args, {'source', 'target', 'start', 'plain' } )
local source_str = new_args['source'] or '';
+
local source_str = new_args['source'] or ''
local pattern = new_args['target'] or '';
+
local pattern = new_args['target'] or ''
local start_pos = tonumber(new_args['start']) or 1;
+
local start_pos = tonumber(new_args['start']) or 1
local plain = new_args['plain'] or true;
+
local plain = new_args['plain'] or true
    
if source_str == '' or pattern == '' then
 
if source_str == '' or pattern == '' then
return 0;
+
return 0
 
end
 
end
   −
plain = str._getBoolean( plain );
+
plain = str._getBoolean( plain )
    
local start = mw.ustring.find( source_str, pattern, start_pos, plain )
 
local start = mw.ustring.find( source_str, pattern, start_pos, plain )
Line 361: Line 393:  
]]
 
]]
 
function str.replace( frame )
 
function str.replace( frame )
local new_args = str._getParameters( frame.args, {'source', 'pattern', 'replace', 'count', 'plain' } );
+
local new_args = str._getParameters( frame.args, {'source', 'pattern', 'replace', 'count', 'plain' } )
local source_str = new_args['source'] or '';
+
local source_str = new_args['source'] or ''
local pattern = new_args['pattern'] or '';
+
local pattern = new_args['pattern'] or ''
local replace = new_args['replace'] or '';
+
local replace = new_args['replace'] or ''
local count = tonumber( new_args['count'] );
+
local count = tonumber( new_args['count'] )
local plain = new_args['plain'] or true;
+
local plain = new_args['plain'] or true
    
if source_str == '' or pattern == '' then
 
if source_str == '' or pattern == '' then
return source_str;
+
return source_str
 
end
 
end
plain = str._getBoolean( plain );
+
plain = str._getBoolean( plain )
    
if plain then
 
if plain then
pattern = str._escapePattern( pattern );
+
pattern = str._escapePattern( pattern )
replace = mw.ustring.gsub( replace, "%%", "%%%%" ); --Only need to escape replacement sequences.
+
replace = mw.ustring.gsub( replace, "%%", "%%%%" ) --Only need to escape replacement sequences.
 
end
 
end
   −
local result;
+
local result
    
if count ~= nil then
 
if count ~= nil then
result = mw.ustring.gsub( source_str, pattern, replace, count );
+
result = mw.ustring.gsub( source_str, pattern, replace, count )
 
else
 
else
result = mw.ustring.gsub( source_str, pattern, replace );
+
result = mw.ustring.gsub( source_str, pattern, replace )
 
end
 
end
   −
return result;
+
return result
 
end
 
end
   Line 392: Line 424:  
     simple function to pipe string.rep to templates.
 
     simple function to pipe string.rep to templates.
 
]]
 
]]
   
function str.rep( frame )
 
function str.rep( frame )
 
local repetitions = tonumber( frame.args[2] )
 
local repetitions = tonumber( frame.args[2] )
Line 418: Line 449:  
local pattern_str = frame.args[1]
 
local pattern_str = frame.args[1]
 
if not pattern_str then
 
if not pattern_str then
return str._error( 'No pattern string specified' );
+
return str._error( 'No pattern string specified' )
 
end
 
end
 
local result = str._escapePattern( pattern_str )
 
local result = str._escapePattern( pattern_str )
 
return result
 
return result
 +
end
 +
 +
--[[
 +
count
 +
This function counts the number of occurrences of one string in another.
 +
]]
 +
function str.count(frame)
 +
local args = str._getParameters(frame.args, {'source', 'pattern', 'plain'})
 +
local source = args.source or ''
 +
local pattern = args.pattern or ''
 +
local plain = str._getBoolean(args.plain or true)
 +
if plain then
 +
pattern = str._escapePattern(pattern)
 +
end
 +
local _, count = mw.ustring.gsub(source, pattern, '')
 +
return count
 +
end
 +
 +
--[[
 +
endswith
 +
This function determines whether a string ends with another string.
 +
]]
 +
function str.endswith(frame)
 +
local args = str._getParameters(frame.args, {'source', 'pattern'})
 +
local source = args.source or ''
 +
local pattern = args.pattern or ''
 +
if pattern == '' then
 +
-- All strings end with the empty string.
 +
return "yes"
 +
end
 +
if mw.ustring.sub(source, -mw.ustring.len(pattern), -1) == pattern then
 +
return "yes"
 +
else
 +
return ""
 +
end
 +
end
 +
 +
--[[
 +
join
 +
 +
Join all non empty arguments together; the first argument is the separator.
 +
Usage:
 +
{{#invoke:String|join|sep|one|two|three}}
 +
]]
 +
function str.join(frame)
 +
local args = {}
 +
local sep
 +
for _, v in ipairs( frame.args ) do
 +
if sep then
 +
if v ~= '' then
 +
table.insert(args, v)
 +
end
 +
else
 +
sep = v
 +
end
 +
end
 +
return table.concat( args, sep or '' )
 
end
 
end
   Line 431: Line 519:  
]]
 
]]
 
function str._getParameters( frame_args, arg_list )
 
function str._getParameters( frame_args, arg_list )
local new_args = {};
+
local new_args = {}
local index = 1;
+
local index = 1
local value;
+
local value
   −
for i,arg in ipairs( arg_list ) do
+
for _, arg in ipairs( arg_list ) do
 
value = frame_args[arg]
 
value = frame_args[arg]
 
if value == nil then
 
if value == nil then
value = frame_args[index];
+
value = frame_args[index]
index = index + 1;
+
index = index + 1
 
end
 
end
new_args[arg] = value;
+
new_args[arg] = value
 
end
 
end
   −
return new_args;
+
return new_args
 
end
 
end
   Line 451: Line 539:  
]]
 
]]
 
function str._error( error_str )
 
function str._error( error_str )
local frame = mw.getCurrentFrame();
+
local frame = mw.getCurrentFrame()
local error_category = frame.args.error_category or 'Errors reported by Module String';
+
local error_category = frame.args.error_category or 'Errors reported by Module String'
local ignore_errors = frame.args.ignore_errors or false;
+
local ignore_errors = frame.args.ignore_errors or false
local no_category = frame.args.no_category or false;
+
local no_category = frame.args.no_category or false
    
if str._getBoolean(ignore_errors) then
 
if str._getBoolean(ignore_errors) then
return '';
+
return ''
 
end
 
end
   −
local error_str = '<strong class="error">String Module Error: ' .. error_str .. '</strong>';
+
local error_str = '<strong class="error">String Module Error: ' .. error_str .. '</strong>'
 
if error_category ~= '' and not str._getBoolean( no_category ) then
 
if error_category ~= '' and not str._getBoolean( no_category ) then
error_str = '[[Category:' .. error_category .. ']]' .. error_str;
+
error_str = '[[Category:' .. error_category .. ']]' .. error_str
 
end
 
end
   −
return error_str;
+
return error_str
 
end
 
end
   Line 472: Line 560:  
]]
 
]]
 
function str._getBoolean( boolean_str )
 
function str._getBoolean( boolean_str )
local boolean_value;
+
local boolean_value
    
if type( boolean_str ) == 'string' then
 
if type( boolean_str ) == 'string' then
boolean_str = boolean_str:lower();
+
boolean_str = boolean_str:lower()
 
if boolean_str == 'false' or boolean_str == 'no' or boolean_str == '0'
 
if boolean_str == 'false' or boolean_str == 'no' or boolean_str == '0'
 
or boolean_str == '' then
 
or boolean_str == '' then
boolean_value = false;
+
boolean_value = false
 
else
 
else
boolean_value = true;
+
boolean_value = true
 
end
 
end
 
elseif type( boolean_str ) == 'boolean' then
 
elseif type( boolean_str ) == 'boolean' then
boolean_value = boolean_str;
+
boolean_value = boolean_str
 
else
 
else
error( 'No boolean value found' );
+
error( 'No boolean value found' )
 
end
 
end
 
return boolean_value
 
return boolean_value
Line 495: Line 583:  
]]
 
]]
 
function str._escapePattern( pattern_str )
 
function str._escapePattern( pattern_str )
return mw.ustring.gsub( pattern_str, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1" );
+
return mw.ustring.gsub( pattern_str, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1" )
 
end
 
end
    
return str
 
return str