Difference between revisions of "Module:String"

From Timelines
Jump to: navigation, search
(replace_plain fix)
(include more generic replacement function)
Line 127: Line 127:
 
     end     
 
     end     
 
      
 
      
     if type( plain ) == 'string' then
+
     plain = str._getBoolean( plain );
        plain = plain:lower();
 
        if plain == 'false' or plain == 'no' or plain == '0' then
 
            plain = false;
 
        else
 
            plain = true;
 
        end   
 
    end
 
  
 
     local start = mw.ustring.find( source_str, pattern, start_pos, plain )
 
     local start = mw.ustring.find( source_str, pattern, start_pos, plain )
Line 145: Line 138:
  
 
--[====[
 
--[====[
replace_plain
+
replace
  
 
This function allows one to replace a target string or pattern within another
 
This function allows one to replace a target string or pattern within another
Line 151: Line 144:
  
 
Usage:
 
Usage:
{{#invoke:String|replace_plain|source_str|pattern_string|replace_string|firstonlyflag}}
+
{{#invoke:String|replace_plain|source_str|pattern_string|replace_string|replacement_count|pattern_flag}}
 
OR
 
OR
{{#invoke:String|replace_plain|source=source_str|pattern=pattern_str|replace=replace_string|firstonly=firstonlyflag}}
+
{{#invoke:String|replace_plain|source=source_str|pattern=pattern_str|replace=replace_string|
 +
  count=replacement_count|plain=pattern_flag}}
  
 
Parameters
 
Parameters
 
     source: The string to search
 
     source: The string to search
     patten: The string or pattern to find within source
+
     pattern: The string or pattern to find within source
 
     replace: The replacement text
 
     replace: The replacement text
     firstonly: Boolean flag indicating that only the first occurence found should be replaced
+
     count: The number of occurences to replace, defaults to all.
 +
    plain: Boolean flag indicating that pattern should be understood as plain
 +
        text and not as a Lua style regular expression, defaults to true
 
]====]
 
]====]
function str.replace_plain( frame )
+
function str.replace( frame )
     local new_args = str._getParameters( frame.args, {'source', 'pattern', 'replace', 'firstonly' } );  
+
     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 firstonly = new_args['firstonly'] or '';
+
     local count = tonumber( new_args['count'] );
     firstonly = firstonly:lower();
+
     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 );
  
     local pattern_plain = mw.ustring.gsub(pattern, '%%', '%%%%');
+
     if plain then
    local replace_plain = mw.ustring.gsub(replace, '%%', '%%%%');
+
        pattern = str._escapePattern( pattern );
 +
        replace = str._escapePattern( replace );
 +
    end
 +
   
 
     local result;
 
     local result;
  
     if firstonly == 'true' or firstonly == 'yes' or firstonly == '1' then
+
     if count ~= nil then
         result = mw.ustring.gsub( source_str, pattern_plain, replace_plain, 1 );
+
         result = mw.ustring.gsub( source_str, pattern, replace, count );
 
     else
 
     else
         result = mw.ustring.gsub( source_str, pattern_plain, replace_plain, n );
+
         result = mw.ustring.gsub( source_str, pattern, replace );
     end
+
     end      
  
 
     return result;
 
     return result;
Line 208: Line 208:
 
     return new_args;
 
     return new_args;
 
end         
 
end         
 +
 +
--[====[
 +
Helper Function to interpret boolean strings
 +
]====]
 +
function str._getBoolean( boolean_str )
 +
    local boolean_value;
 +
   
 +
    if type( boolean_str ) == 'string' then
 +
        boolean_str = boolean_str:lower();
 +
        if boolean_str == 'false' or boolean_str == 'no' or boolean_str == '0' then
 +
            boolean_value = false;
 +
        else
 +
            boolean_value = true;
 +
        end   
 +
    elseif type( boolean_str ) == 'boolean' then
 +
        boolean_value = boolean_str;
 +
    else
 +
        error( 'No boolean value found' );
 +
    end   
 +
    return boolean_value
 +
end
 +
 +
--[====[
 +
Helper function that escapes all pattern characters so that they will be treated
 +
as plain text.
 +
]====]
 +
function str._escapePattern( pattern_str )
 +
    return mw.ustring.gsub( pattern_str, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1" );
 +
end
  
 
return str
 
return str

Revision as of 11:31, 24 February 2013

Documentation for this module may be created at Module:String/doc

local str = {}

function str.len( frame )
    return mw.ustring.len( frame.args.s )
end

function str.sub( frame )
    return mw.ustring.sub( frame.args.s, tonumber( frame.args.i ), tonumber( frame.args.j ) )
end

function str.sublength( frame )
    local i = tonumber( frame.args.i ) or 0
    local len = tonumber( frame.args.len )
    return mw.ustring.sub( frame.args.s, i + 1, len and ( i + len ) )
end

function str.match( frame )
    return mw.ustring.match( frame.args.s, frame.args.pattern, tonumber( frame.args.i ) )
end

--[====[
pos

This function returns a single character from the target string at position pos.

Usage:
{{#invoke:String|pos|target_string|index_value}}
OR
{{#invoke:String|pos|target=target_string|pos=index_value}}

Parameters
    target: The string to search
    pos: The index for the character to return

If invoked using named parameters, Mediawiki will automatically remove any leading or
trailing whitespace from the target string.  In some circumstances this is desirable, in 
other cases one may want to preserve the whitespace.

The first character has an index value of 1.

If one requests a negative value, this function will select a character by counting backwards 
from the end of the string.  In other words pos = -1 is the same as asking for the last character.

A requested value of zero, or a value greater than the length of the string returns an error.
]====]
function str.pos( frame )
    local new_args = str._getParameters( frame.args, {'target', 'pos'} );
    local target_str = new_args['target'] or '';
    local pos = tonumber( new_args['pos'] ) or 0;

    if pos == 0 or math.abs(pos) > mw.ustring.len( target_str ) then
        return '<strong class="error">String index out of range</strong>';
    end    
    
    return mw.ustring.sub( target_str, pos, pos );
end

--[====[
str_find

This function duplicates the behavior of {{str_find}}, including all of its quirks.
This is provided in order to support existing templates, but is NOT RECOMMENDED for 
new code and templates.  New code is recommended to use the "find" function instead.

Returns the first index in "source" that is a match to "target".  Indexing is 1-based,
and the function returns -1 if the "target" string is not present in "source".

Important Note: If the "target" string is empty / missing, this function returns a
value of "1", which is generally unexpected behavior, and must be accounted for
separatetly.
]====]
function str.str_find( frame )
    local new_args = str._getParameters( frame.args, {'source', 'target'} );
    local source_str = new_args['source'] or '';
    local target_str = new_args['target'] or '';

    if target_str == '' then
        return 1;
    end    
    
    local start = mw.ustring.find( source_str, target_str, 1, true )
    if start == nil then
        start = -1
    end
    
    return start
end

--[====[
find

This function allows one to search for a target string or pattern within another
string.

Usage:
{{#invoke:String|find|source_str|target_string|start_index|plain_flag}}
OR
{{#invoke:String|find|source=source_str|target=target_str|start=start_index|plain=plain_flag}}

Parameters
    source: The string to search
    target: The string or pattern to find within source
    start: The index within the source string to start the search, defaults to 1
    plain: Boolean flag indicating that target should be understood as plain
        text and not as a Lua style regular expression, defaults to true

If invoked using named parameters, Mediawiki will automatically remove any leading or
trailing whitespace from the parameter.  In some circumstances this is desirable, in 
other cases one may want to preserve the whitespace.

This function returns the first index >= "start" where "target" can be found 
within "source".  Indices are 1-based.  If "target" is not found, then this 
function returns 0.  If either "source" or "target" are missing / empty, this
function also returns 0.

This function should be safe for UTF-8 strings.
]====]
function str.find( frame )
    local new_args = str._getParameters( frame.args, {'source', 'target', 'start', 'plain' } ); 
    local source_str = new_args['source'] or '';
    local pattern = new_args['target'] or '';
    local start_pos = tonumber(new_args['start']) or 1;
    local plain = new_args['plain'] or true;
        
    if source_str == '' or pattern == '' then
        return 0;
    end    
    
    plain = str._getBoolean( plain );

    local start = mw.ustring.find( source_str, pattern, start_pos, plain )
    if start == nil then
        start = 0
    end
    
    return start
end

--[====[
replace

This function allows one to replace a target string or pattern within another
string.

Usage:
{{#invoke:String|replace_plain|source_str|pattern_string|replace_string|replacement_count|pattern_flag}}
OR
{{#invoke:String|replace_plain|source=source_str|pattern=pattern_str|replace=replace_string|
   count=replacement_count|plain=pattern_flag}}

Parameters
    source: The string to search
    pattern: The string or pattern to find within source
    replace: The replacement text
    count: The number of occurences to replace, defaults to all.
    plain: Boolean flag indicating that pattern should be understood as plain
        text and not as a Lua style regular expression, defaults to true 
]====]
function str.replace( frame )
    local new_args = str._getParameters( frame.args, {'source', 'pattern', 'replace', 'count', 'plain' } ); 
    local source_str = new_args['source'] or '';
    local pattern = new_args['pattern'] or '';
    local replace = new_args['replace'] or '';
    local count = tonumber( new_args['count'] );
    local plain = new_args['plain'] or true;
        
    if source_str == '' or pattern == '' then
        return source_str;
    end    
    plain = str._getBoolean( plain );

    if plain then
        pattern = str._escapePattern( pattern );
        replace = str._escapePattern( replace );
    end
    
    local result;

    if count ~= nil then
        result = mw.ustring.gsub( source_str, pattern, replace, count );
    else
        result = mw.ustring.gsub( source_str, pattern, replace );
    end        

    return result;
end

--[====[
Helper function that populates the argument list given that user may need to use a mix of
named and unnamed parameters.  This is relevant because named parameters are not
identical to unnamed parameters due to string trimming, and when dealing with strings
we sometimes want to either preserve or remove that whitespace depending on the application.
]====]
function str._getParameters( frame_args, arg_list )
    local new_args = {};
    local index = 1;
    local value;
    
    for i,arg in ipairs( arg_list ) do
        value = frame_args[arg]
        if value == nil then
            value = frame_args[index];
            index = index + 1;
        end
        new_args[arg] = value;
    end
    
    return new_args;
end        

--[====[
Helper Function to interpret boolean strings
]====]
function str._getBoolean( boolean_str )
    local boolean_value;
    
    if type( boolean_str ) == 'string' then
        boolean_str = boolean_str:lower();
        if boolean_str == 'false' or boolean_str == 'no' or boolean_str == '0' then
            boolean_value = false;
        else
            boolean_value = true;
        end    
    elseif type( boolean_str ) == 'boolean' then
        boolean_value = boolean_str;
    else
        error( 'No boolean value found' );
    end    
    return boolean_value
end

--[====[
Helper function that escapes all pattern characters so that they will be treated 
as plain text.
]====]
function str._escapePattern( pattern_str )
    return mw.ustring.gsub( pattern_str, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1" );
end

return str