如何查找和替换字符串中出现的所有子字符串?

时间:2021-04-21 19:19:11

I need to search a string and edit the formatting of it.

我需要搜索一个字符串并编辑它的格式。

So far I can replace the first occurrence of the string, but I am unable to do so with the next occurrences of this string.

到目前为止,我可以替换字符串的第一次出现,但是我不能替换这个字符串的下一次出现。

This is what I have working, sort of:

这就是我的工作,

if(chartDataString.find("*A") == string::npos){ return;}
else{chartDataString.replace(chartDataString.find("*A"), 3,"[A]\n");}

If it doesn't find the string, nothing prints at all, so that's not good.

如果它找不到弦,就不会有任何东西打印出来,这就不好了。

I know I need to loop through the entire string chartDataString and replace all occurrences. I know there are a lot of similar posts to this but I don't understand (like this Replace substring with another substring C++)

我知道我需要遍历整个字符串chartDataString并替换所有出现的内容。我知道有很多类似的文章但是我不明白(比如用另一个子字符串c++替换子字符串)

I've also tried to do something like this to loop over the string:

我也试过这样做来循环字符串:

string toSearch = chartDataString;
string toFind = "*A:";
for (int i = 0; i<toSearch.length() - toFind.length(); i++){
   if(toSearch.substr(i, toFind.length()) == toFind){
       chartDataString.replace(chartDataString.find(toFind), 3, "[A]\n");   
   }
}

EDIT taking into consideration suggestions, this in theory should work, but I don't know why it doesn't

考虑到建议,这在理论上应该行得通,但我不知道为什么行不通

size_t startPos=0;
string myString = "*A";
while(string::npos != (startPos = chartDataString.find(myString, startPos))){
    chartDataString.replace(chartDataString.find(myString, startPos), 3, "*A\n");
    startPos = startPos + myString.length();
}   

6 个解决方案

#1


18  

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();
}

#2


2  

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

find函数接受第二个可选参数:开始搜索的位置。默认情况下这是零。

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.

开始搜索下一个匹配项的一个好位置是插入前一个替换项的位置,加上替换项的长度。例如,如果我们在位置7插入一个长度为3的字符串,那么下一个查找应该从位置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.

如果搜索字符串恰好是替换的子字符串,这种方法将避免无限循环。想象一下,如果您尝试用模拟替换所有出现的日志,但是不要跳过替换。

#3


2  

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.

基本上,只要您能够找到一个from的实例,然后附加中间文本,并向下一个实例前进,您就会循环。最后,在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.)

(如果您打算使用c++进行大量编程,那么最好习惯使用迭代器,如上面所示,而不是使用std::string的特殊成员函数。像上面这样的东西可以用于任何c++容器类型,出于这个原因,它们更符合习惯用法。

#4


1  

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

如果有boost,您可以使用以下工具:

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.

在不修改原始字符串的情况下执行修改。

Hope it helps.

希望它可以帮助。

Cheers,

欢呼,

Guy

的家伙

#5


0  

/// Returns a version of 'str' where every occurrence of
/// 'find' is substituted by 'replace'.
/// - Inspired by James Kanze.
/// - http://*.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" );
    }
}

#6


0  

Quick-baked version, but working:) version:

快烤版,但工作:)版本:

string replace(const string& data, const string& substr, const string& replacement)
{
    string res;
    string::const_iterator b = cbegin(data);
    string::const_iterator e = cend(data);

    string::const_iterator pos = search(b, e, cbegin(substr), cend(substr));
    while (pos != e)
    {
        copy(b, pos, back_inserter(res));
        copy(begin(replacement), end(replacement), back_inserter(res));

        b = pos + substr.size();
        pos = search(b, e, cbegin(substr), cend(substr));
    }
    copy(b, e, back_inserter(res));

    return res;
}

#1


18  

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();
}

#2


2  

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

find函数接受第二个可选参数:开始搜索的位置。默认情况下这是零。

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.

开始搜索下一个匹配项的一个好位置是插入前一个替换项的位置,加上替换项的长度。例如,如果我们在位置7插入一个长度为3的字符串,那么下一个查找应该从位置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.

如果搜索字符串恰好是替换的子字符串,这种方法将避免无限循环。想象一下,如果您尝试用模拟替换所有出现的日志,但是不要跳过替换。

#3


2  

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.

基本上,只要您能够找到一个from的实例,然后附加中间文本,并向下一个实例前进,您就会循环。最后,在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.)

(如果您打算使用c++进行大量编程,那么最好习惯使用迭代器,如上面所示,而不是使用std::string的特殊成员函数。像上面这样的东西可以用于任何c++容器类型,出于这个原因,它们更符合习惯用法。

#4


1  

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

如果有boost,您可以使用以下工具:

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.

在不修改原始字符串的情况下执行修改。

Hope it helps.

希望它可以帮助。

Cheers,

欢呼,

Guy

的家伙

#5


0  

/// Returns a version of 'str' where every occurrence of
/// 'find' is substituted by 'replace'.
/// - Inspired by James Kanze.
/// - http://*.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" );
    }
}

#6


0  

Quick-baked version, but working:) version:

快烤版,但工作:)版本:

string replace(const string& data, const string& substr, const string& replacement)
{
    string res;
    string::const_iterator b = cbegin(data);
    string::const_iterator e = cend(data);

    string::const_iterator pos = search(b, e, cbegin(substr), cend(substr));
    while (pos != e)
    {
        copy(b, pos, back_inserter(res));
        copy(begin(replacement), end(replacement), back_inserter(res));

        b = pos + substr.size();
        pos = search(b, e, cbegin(substr), cend(substr));
    }
    copy(b, e, back_inserter(res));

    return res;
}