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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20406744/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 23:06:51  来源:igfitidea点击:

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

c++stringalgorithmstr-replace

提问by Sarah

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

回答by Vlad from Moscow

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

回答by Guy Avraham

In case boostis 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.

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

回答by Kaz

The findfunction 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 findshould begin at position 10.

开始搜索下一个匹配的一个好位置是插入前一个替换的位置,加上该替换的长度。例如,如果我们在位置 7 插入一个长度为 3 的字符串,那么下一个find应该从位置 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 logwith analog, but don't skip over the replacement.

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

回答by James Kanze

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,附加中间文本 和to,然后前进到 的下一个实例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++ 容器类型,因此,更符合习惯。)

回答by Adolfo

/// 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" );
    }
}

回答by Ben Corbett

Use std::regex_replace available with C++11. This does exactly what you want and more.

使用 C++11 提供的 std::regex_replace。这正是您想要的,甚至更多。

https://en.cppreference.com/w/cpp/regex/regex_replace

https://en.cppreference.com/w/cpp/regex/regex_replace

std::string const result = std::regex_replace( chartDataString, std::regex( "\*A" ), "[A]\n" );

回答by Nat

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