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 |