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

时间:2013-12-05 17:30:55

标签: c++ string algorithm str-replace

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

到目前为止,我可以替换第一次出现的字符串,但是我无法在下一次出现此字符串时这样做。

这就是我的工作,有点像:

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

如果找不到字符串,则根本没有打印,所以这不好。

我知道我需要遍历整个字符串chartDataString并替换所有出现的内容。我知道有很多类似的帖子,但我不明白(比如Replace substring with another substring C++

我也尝试过这样的事情来循环遍历字符串:

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 考虑到建议,这在理论上应该有效,但我不知道为什么它没有

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

8 个答案:

答案 0 :(得分:20)

尝试以下

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

答案 1 :(得分:6)

如果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);

对原始字符串执行修改,或者

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

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

答案 2 :(得分:2)

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

开始搜索下一场比赛的好位置是插入先前替换的位置,加上替换的长度。例如,如果我们在第7位插入长度为3的字符串,那么下一个find应该从位置10开始。

如果搜索字符串碰巧是替换的子字符串,则此方法将避免无限循环。想象一下,如果您尝试用log替换所有出现的analog,但不要跳过替换。

答案 3 :(得分:2)

执行此操作相当尴尬(可能效率不高) 地点。我通常使用以下行的函数:

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

基本上,只要你能找到一个实例,你就会循环 from,附加中间文字和to,并推进 到from的下一个实例。最后,您附加任何文本 在from的最后一个实例之后。

(如果你要在C ++中做很多编程,可能就是这样 一个好主意习惯使用迭代器,如上所述, 而不是std::string的特殊成员函数。 像上面这样的东西可以用于任何C ++ 容器类型,因此更加惯用。)

答案 4 :(得分:1)

使用C ++ 11附带的std :: regex_replace。这正是您想要的,还有更多。

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

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

如果您需要反转的字符串大小不同:

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

答案 7 :(得分:0)

string replaceAll(string del, string replace, string line){

int len=del.length();
string output="[Programming Error]";
if(line.find(del)!=-1){
    do{
        output=line.replace(line.find(del),len,replace);
    }while(output.find(del)!=-1);
}
return output;

}