Module:String: Difference between revisions
Content added Content deleted
Enwikipedia>RexxS (update renamed variable) |
Enwikipedia>RexxS (Implement the merge of Module:Join, Module:Str endswith, Module:PatternCount and Module:Text count into this module per their TfDs. Review and discussion is at https://en.wikipedia.org/w/index.php?title=Module_talk:String&oldid=899040020#Edit_request_to_implement_merges) |
||
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 151: | Line 151: | ||
function str._match( s, pattern, start, match_index, plain_flag, 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 173: | ||
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 201: | ||
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 |
||
-- 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_flag, nomatch ) |
return str._match( s, pattern, start, match_index, plain_flag, nomatch ) |
||
Line 248: | Line 248: | ||
]] |
]] |
||
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 274: | ||
]] |
]] |
||
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 320: | ||
]] |
]] |
||
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 361: | ||
]] |
]] |
||
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, "%%", "%%%%" ) |
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 392: | ||
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 417: | ||
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 487: | ||
]] |
]] |
||
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 |
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 507: | ||
]] |
]] |
||
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 528: | ||
]] |
]] |
||
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 551: | ||
]] |
]] |
||
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 |
||