How to find and replace all occurrences of a substring in a string?

早过忘川 提交于 2019-11-30 18:35:15

try the following

const std::string s = "*A";
const std::string t = "*A\n";

std::string::size_type n = 0;
while ( ( n = chartDataString.find( s, n ) ) != std::string::npos )
{
    chartDataString.replace( n, s.size(), t );
    n += t.size();
}
Guy Avraham

In case boost is available, you can use the following:

std::string origStr = "this string has *A and then another *A";
std::string subStringToRemove = "*A";
std::string subStringToReplace = "[A]";

boost::replace_all(origStr , subStringToRemove , subStringToReplace);

To perform the modification on the original string, OR

std::string result = boost::replace_all_copy(origStr , subStringToRemove , subStringToReplace);

To perform the modifications without modifying the original string.

The find function takes an optional second argument: the position from which to begin searching. By default this is zero.

A good position to begin searching for the next match is the position where the previous replacement was inserted, plus that replacement's length. For instance if we insert a string of length 3 at position 7, then the next find should begin at position 10.

If the search string happens to be a substring of the replacement, this approach will avoid an infinite loop. Imagine if you try to replace all occurrences of log with analog, but don't skip over the replacement.

It's fairly awkward (and probably not too efficient) to do it in place. I usually use a function along the lines of:

std::string
replaceAll( std::string const& original, std::string const& from, std::string const& to )
{
    std::string results;
    std::string::const_iterator end = original.end();
    std::string::const_iterator current = original.begin();
    std::string::const_iterator next = std::search( current, end, from.begin(), from.end() );
    while ( next != end ) {
        results.append( current, next );
        results.append( to );
        current = next + from.size();
        next = std::search( current, end, from.begin(), from.end() );
    }
    results.append( current, next );
    return results;
}

Basically, you loop as long as you can find an instance of from, appending the intermediate text and to, and advancing to the next instance of from. At the end, you append any text after the last instance of from.

(If you're going to do much programming in C++, it's probably a good idea to get used to using iterators, like the above, rather than the special member functions of std::string. Things like the above can be made to work with any of the C++ container types, and for this reason, are more idiomatic.)

/// Returns a version of 'str' where every occurrence of
/// 'find' is substituted by 'replace'.
/// - Inspired by James Kanze.
/// - http://stackoverflow.com/questions/20406744/
std::string replace_all(
    const std::string & str ,   // where to work
    const std::string & find ,  // substitute 'find'
    const std::string & replace //      by 'replace'
) {
    using namespace std;
    string result;
    size_t find_len = find.size();
    size_t pos,from=0;
    while ( string::npos != ( pos=str.find(find,from) ) ) {
        result.append( str, from, pos-from );
        result.append( replace );
        from = pos + find_len;
    }
    result.append( str, from , string::npos );
    return result;
/*
    This code might be an improvement to James Kanze's
    because it uses std::string methods instead of
    general algorithms [as 'std::search()'].
*/
}

int main() {
    {
        std::string test    = "*A ... *A ... *A ...";
        std::string changed = "*A\n ... *A\n ... *A\n ...";

        assert( changed == replace_all( test, "*A", "*A\n" ) );
    }
    {
        std::string GB = "My gorila ate the banana";

        std::string gg = replace_all( GB, "gorila", "banana" );
        assert( gg ==  "My banana ate the banana" );
        gg = replace_all( gg, "banana", "gorila"  );
        assert( gg ==  "My gorila ate the gorila" );

        std::string bb = replace_all( GB, "banana", "gorila" );
        assert( gg ==  "My gorila ate the gorila" );
        bb = replace_all( bb, "gorila" , "banana" );
        assert( bb ==  "My banana ate the banana" );
    }
    {
        std::string str, res;

        str.assign( "ababaabcd" );
        res = replace_all( str, "ab", "fg");
        assert( res == "fgfgafgcd" );

        str="aaaaaaaa"; assert( 8==str.size() );
        res = replace_all( str, "aa", "a" );
        assert( res == "aaaa" );
        assert( "" == replace_all( str, "aa", "" ) );

        str = "aaaaaaa"; assert( 7==str.size() );
        res = replace_all( str, "aa", "a" );
        assert( res == "aaaa" );

        str = "..aaaaaa.."; assert( 10==str.size() );
        res = replace_all( str, "aa", "a" );
        assert( res == "..aaa.." );

        str = "baaaac"; assert( 6==str.size() );
        res = replace_all( str, "aa", "" );
        assert( res == "bc" );
    }
}

If ever the strings you need to invert are not of the same size:

void            Replace::replace(std::string & str, std::string const & s1, std::string const & s2)
{
    size_t      pos;

    pos = 0;
    while ((pos = str.find(s1, pos)) != std::string::npos)
    {
        str.erase(pos, s1.length());
        str.insert(pos, s2);
        pos += s2.length();
    }
    return ;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!