什么是有效的方法来取代一个字符的所有出现与另一个字符在std::字符串?


当前回答

如果你想替换一个以上的字符,并且只处理std::string,那么这个代码片段可以工作,用sReplace替换sHaystack中的sNeedle,而且sNeedle和sReplace不需要相同的大小。这个例程使用while循环替换所有发生的事件,而不是只替换从左到右找到的第一个事件。

while(sHaystack.find(sNeedle) != std::string::npos) {
  sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
}

其他回答

这个问题集中在字符替换上,但是,我发现这个页面非常有用(尤其是Konrad的评论),我想分享这个更通用的实现,它也允许处理子字符串:

std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) {
    size_t start_pos = 0;
    while((start_pos = str.find(from, start_pos)) != std::string::npos) {
        str.replace(start_pos, from.length(), to);
        start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
    }
    return str;
}

用法:

std::cout << ReplaceAll(string("Number Of Beans"), std::string(" "), std::string("_")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("X")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("h")) << std::endl;

输出:

Number_Of_Beans XXjXugtXty hhjhugthty


编辑:

以上可以以一种更合适的方式实现,如果性能是您所关心的,通过不返回任何(void)并执行“就地”更改;也就是说,通过直接修改字符串参数str,通过引用而不是值传递。这将通过覆盖原始字符串来避免额外的开销。

代码:

static inline void ReplaceAll2(std::string &str, const std::string& from, const std::string& to)
{
    // Same inner code...
    // No return statement
}

希望这对其他人有所帮助…

我想我也会加入促进方案:

#include <boost/algorithm/string/replace.hpp>

// in place
std::string in_place = "blah#blah";
boost::replace_all(in_place, "#", "@");

// copy
const std::string input = "blah#blah";
std::string output = boost::replace_all_copy(input, "#", "@");

这个工作!我在书店应用程序中使用了类似的方法,其中库存存储在CSV(类似于.dat文件)中。但在单字符的情况下,意味着替换者只是一个单字符,例如'|',它必须在双引号"|"中,以避免抛出无效的转换const char。

#include <iostream>
#include <string>

using namespace std;

int main()
{
    int count = 0;  // for the number of occurences.
    // final hold variable of corrected word up to the npos=j
    string holdWord = "";
    // a temp var in order to replace 0 to new npos
    string holdTemp = "";
    // a csv for a an entry in a book store
    string holdLetter = "Big Java 7th Ed,Horstman,978-1118431115,99.85";

    // j = npos
    for (int j = 0; j < holdLetter.length(); j++) {

        if (holdLetter[j] == ',') {

            if ( count == 0 ) 
            {           
                holdWord = holdLetter.replace(j, 1, " | ");      
            }
            else {

                string holdTemp1 = holdLetter.replace(j, 1, " | ");

                // since replacement is three positions in length,
                // must replace new replacement's 0 to npos-3, with
                // the 0 to npos - 3 of the old replacement 
                holdTemp = holdTemp1.replace(0, j-3, holdWord, 0, j-3); 

                holdWord = "";

                holdWord = holdTemp;

            }
            holdTemp = "";
            count++;
        }
    } 
    cout << holdWord << endl;
    return 0;
}

// result:
Big Java 7th Ed | Horstman | 978-1118431115 | 99.85

我目前使用CentOS,所以我的编译器版本如下。c++版本(g++), c++ 98默认值:

g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

这不是标准库中缺少的唯一方法,它本来是低级别的。 这个用例和许多其他用例由通用库涵盖,例如:

波科 绳降 提高 QtCore

QtCore & QString有我的偏好:它支持UTF8,使用更少的模板,这意味着可以理解的错误和更快的编译。它使用了“q”前缀,使命名空间变得不必要,并简化了头文件。 Boost经常生成可怕的错误消息和缓慢的编译时间。 POCO似乎是一种合理的妥协。

一个简单的查找和替换单个字符是这样的:

s.find("x"), 1, "y")

要对整个字符串执行此操作,最简单的方法是循环,直到s.find开始返回npos。我认为您还可以捕获range_error来退出循环,但这有点丑陋。