std::string中用另一个字符替换所有出现的字符的有效方法是什么?

#1 楼

std::string不包含此类功能,但您可以使用replace标头中的独立algorithm函数。

#include <algorithm>
#include <string>

void some_func() {
  std::string s = "example string";
  std::replace( s.begin(), s.end(), 'x', 'y'); // replace all 'x' to 'y'
}


评论


std :: string是专门设计用于处理字符序列的容器。链接

– Kirill V. Lyadvinsky
2010年5月24日上午11:41

不幸的是,这仅允许将一个字符替换为另一个字符。它不能用更多的字符(即,用字符串)替换一个字符。有没有办法用更多字符进行搜索替换?

– SasQ
2012年8月9日在9:26

@Kirill V. Lyadvinsky如果我只想删除一个事件,该怎么办。

– SIFE
2012年11月22日14:54

@ KirillV.Lyadvinsky:当我使用此方法将所有x替换为y时,无论原始字符串是什么,结果都是冗长的y字符串。我很好奇您认为这是问题所在。 (代码与您编写的完全相同)

–超然
13-10-17在12:08

@Transcendent:这就是std :: string :: replace()而不是std :: replace()的情况! “ x”(字符)被隐式转换为size_t [值120],因此整个字符串或字符串的一部分(或部分)将填充120个“ y”副本。

– IBue
15年2月19日在18:41

#2 楼

问题集中在character的替换上,但是,正如我发现此页面非常有用(尤其是Konrad的评论),我想分享这个更通用的实现,它也可以处理substrings
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
}


希望这对其他人有帮助...

评论


在源字符串很大并且要替换的字符串多次出现的情况下,这会带来性能问题。 string :: replace()将被多次调用,这会导致很多字符串副本。请参阅我的解决该问题的解决方案。

– minastaros
2015年4月21日在6:44



Nit提前:按地址=>按引用。无论是地址还是实现细节。

– Max Truxa
15年5月18日在16:16

您实际上应该检查from字符串是否为空,否则将发生无限循环。

–新手
2015年9月5日在2:23

#3 楼

我还以为我会加入升压解决方案:

#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, "#", "@");


评论


然后,您会为编译器缺少一些-I标志,以使其在系统上找到Boost库。也许您甚至需要先安装它。

–马丁·乌丁
19年5月17日在9:56

上面的方法更有效,因为它是由std lib提供的。

– hfrmobile
3月20日10:49

#4 楼

想象一下一个大的二进制Blob,其中所有0x00字节均应由“ \ 1 \ x30”替换,而所有0x01字节均应由“ \ 1 \ x31”替换,因为传输协议不允许\ 0字节。

在下列情况:


替换字符串和要替换的字符串具有不同的长度,
在源字符串和
中有很多替换字符串出现源字符串很大,

所提供的解决方案无法应用(因为它们仅替换单个字符)或存在性能问题,因为它们会多次调用string :: replace并生成该大小的副本一遍又一遍的斑点。
(我不知道boost解决方案,也许从这个角度来看还可以)

这遍历了源字符串中所有出现的内容并构建了新的一次一串:

void replaceAll(std::string& source, const std::string& from, const std::string& to)
{
    std::string newString;
    newString.reserve(source.length());  // avoids a few memory allocations

    std::string::size_type lastPos = 0;
    std::string::size_type findPos;

    while(std::string::npos != (findPos = source.find(from, lastPos)))
    {
        newString.append(source, lastPos, findPos - lastPos);
        newString += to;
        lastPos = findPos + from.length();
    }

    // Care for the rest after last occurrence
    newString += source.substr(lastPos);

    source.swap(newString);
}


评论


到目前为止,这是仅基于STL构建的最佳解决方案。如果您打算在任何地方使用自定义功能以方便使用,请使其成为此功能。

–罗杰·桑德斯
1月29日0:41

#5 楼

一个简单的查找和替换单个字符的操作如下:

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

要对整个字符串执行此操作,最简单的方法是循环播放直到您的s.find开始返回npos。我想您也可以抓住range_error退出循环,但这有点难看。

评论


当要替换的字符数比字符串的长度小时,这可能是一个合适的解决方案,但扩展性不好。随着原始字符串中需要替换的字符比例增加,此方法将及时接近O(N ^ 2)。

– andand
2010年5月24日14:37

真正。我的一般哲学是做容易(写和读)的事情,直到效率低下导致真正的问题为止。在某些情况下,您可能会有过分的弦乐,其中O(N ** 2)很重要,但是我的弦乐有99%的时间小于或等于1K。

– T.E.D.
10 May 25'3:40

...话虽如此,我更喜欢Kirill的方法(并且已经投票赞成)。

– T.E.D.
2010年5月25日下午3:41

如果找不到“ x”会怎样?另外,为什么要使用双括号?

– Prasath Govind
15年8月25日在11:26

@PrasathGovind-我只是显示所需的呼叫(因此“类似”)。重要的但模糊的细节(如正确的错误处理)留给读者练习。至于“双括号”,我不确定它们是什么,或者您在说什么。对我来说,“括号”是{字符。我不知道什么是“双括号”。也许您有某种字体问题?

– T.E.D.
15年8月25日在12:54

#6 楼

如果您要替换多个字符,并且仅处理std::string,那么此代码段将起作用,用sReplace替换sHaystack中的sNeedle,并且sNeedle和sReplace的大小不必相同。此例程使用while循环替换所有出现的内容,而不仅仅是从左到右找到的第一个。

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


评论


这是O(n ^)。您可以在O(n)时间内完成。

–孙长明
16-09-29在9:30

@ChangmingSun您表示哪个O(n)解决方案?

– habakuk
17年11月23日在10:20

如果kNeedle恰好是sReplace的子字符串,则将无限循环。

–骄傲
1月11日23:39

此外,还有两次查找呼叫。考虑使该结果成为临时变量。

–卢克·布鲁姆(Luc Bloom)
1月20日9:25

#7 楼

正如Kirill所建议的那样,要么使用replace方法,要么沿着字符串迭代以独立替换每个char。

或者,您可以根据需要执行find方法或find_first_of方法。这些解决方案都无法一劳永逸地完成工作,但是您应该使用几行额外的代码来使它们适合您。 :-)

#8 楼

那Abseil StrReplaceAll呢?来自头文件:

// This file defines `absl::StrReplaceAll()`, a general-purpose string
// replacement function designed for large, arbitrary text substitutions,
// especially on strings which you are receiving from some other system for
// further processing (e.g. processing regular expressions, escaping HTML
// entities, etc.). `StrReplaceAll` is designed to be efficient even when only
// one substitution is being performed, or when substitution is rare.
//
// If the string being modified is known at compile-time, and the substitutions
// vary, `absl::Substitute()` may be a better choice.
//
// Example:
//
// std::string html_escaped = absl::StrReplaceAll(user_input, {
//                                                {"&", "&amp;"},
//                                                {"<", "&lt;"},
//                                                {">", "&gt;"},
//                                                {"\"", "&quot;"},
//                                                {"'", "&#39;"}});


#9 楼

#include <iostream>
#include <string>
using namespace std;
// Replace function..
string replace(string word, string target, string replacement){
    int len, loop=0;
    string nword="", let;
    len=word.length();
    len--;
    while(loop<=len){
        let=word.substr(loop, 1);
        if(let==target){
            nword=nword+replacement;
        }else{
            nword=nword+let;
        }
        loop++;
    }
    return nword;

}
//Main..
int main() {
  string word;
  cout<<"Enter Word: ";
  cin>>word;
  cout<<replace(word, "x", "y")<<endl;
  return 0;
}


评论


如果单词很长,则在调用该函数时可能会有很多开销。您可以通过将单词,目标和替换内容作为const-references进行优化。

– TreebledJ
19年2月21日在8:49

#10 楼

在简单的情况下,无需使用任何其他库(然后已使用std :: string),该方法就可以很好地工作(已在使用)。

在some_string中将所有出现的字符a替换为字符b:

for (size_t i = 0; i < some_string.size(); ++i) {
    if (some_string[i] == 'a') {
        some_string.replace(i, 1, "b");
    }
}


如果字符串很大或有多个替换调用是问题,则可以应用此答案中提到的技术:https://stackoverflow.com/a/29752943/3622300

#11 楼

老派:-)

std::string str = "H:/recursos/audio/youtube/libre/falta/"; 

for (int i = 0; i < str.size(); i++) {
    if (str[i] == '/') {
        str[i] = '\';
    }
}

std::cout << str;


结果:


H:\ recursos \ audio \ youtube \ libre \ falta \


#12 楼

为了完整起见,这是使用std::regex的方法。
 #include <regex>
#include <string>

int main()
{
    const std::string s = "example string";
    const std::string r = std::regex_replace(s, std::regex("x"), "y");
}
 


#13 楼

这可行!我在书店应用中使用了与此类似的东西,其中库存存储在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.


#14 楼

如果您愿意使用std::string,则可以按原样使用此示例应用程序的strsub函数,如果希望采用不同类型或一组参数来实现大致相同的目标,请对其进行更新。基本上,它使用std::string的属性和功能来快速擦除匹配的字符集,并将所需的字符直接插入std::string中。每次执行此替换操作时,偏移量都会更新,如果它仍然可以找到匹配的字符进行替换,并且由于无法替换而无法替换,它将返回上次更新后的状态的字符串。

#include <iostream>
#include <string>

std::string strsub(std::string stringToModify,
                   std::string charsToReplace,
                   std::string replacementChars);

int main()
{
    std::string silly_typos = "annoiiyyyng syyyllii tiipos.";

    std::cout << "Look at these " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos, "yyy", "i");
    std::cout << "After a little elbow-grease, a few less " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos, "ii", "y");

    std::cout << "There, no more " << silly_typos << std::endl;
    return 0;
}

std::string strsub(std::string stringToModify,
                   std::string charsToReplace,
                   std::string replacementChars)
{
    std::string this_string = stringToModify;

    std::size_t this_occurrence = this_string.find(charsToReplace);
    while (this_occurrence != std::string::npos)
    {
        this_string.erase(this_occurrence, charsToReplace.size());
        this_string.insert(this_occurrence, replacementChars);
        this_occurrence = this_string.find(charsToReplace,
                                           this_occurrence + replacementChars.size());
    }

    return this_string;
}


如果您不想依靠使用std::string s作为参数,因此可以传递C样式的字符串,则可以在下面看到更新的示例:

#include <iostream>
#include <string>

std::string strsub(const char * stringToModify,
                   const char * charsToReplace,
                   const char * replacementChars,
                   uint64_t sizeOfCharsToReplace,
                   uint64_t sizeOfReplacementChars);

int main()
{
    std::string silly_typos = "annoiiyyyng syyyllii tiipos.";

    std::cout << "Look at these " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos.c_str(), "yyy", "i", 3, 1);
    std::cout << "After a little elbow-grease, a few less " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos.c_str(), "ii", "y", 2, 1);

    std::cout << "There, no more " << silly_typos << std::endl;
    return 0;
}

std::string strsub(const char * stringToModify,
                   const char * charsToReplace,
                   const char * replacementChars,
                   uint64_t sizeOfCharsToReplace,
                   uint64_t sizeOfReplacementChars)
{
    std::string this_string = stringToModify;

    std::size_t this_occurrence = this_string.find(charsToReplace);
    while (this_occurrence != std::string::npos)
    {
        this_string.erase(this_occurrence, sizeOfCharsToReplace);
        this_string.insert(this_occurrence, replacementChars);
        this_occurrence = this_string.find(charsToReplace,
            this_occurrence + sizeOfReplacementChars);
    }

    return this_string;
}


#15 楼

这是我以最大的DRI精神推出的解决方案。
它将在sHaystack中搜索sNeedle并将其替换为sReplace,
nTimes如果非零,则所有sNeedle都出现。
它不会在替换的文本中再次搜索。

std::string str_replace(
    std::string sHaystack, std::string sNeedle, std::string sReplace, 
    size_t nTimes=0)
{
    size_t found = 0, pos = 0, c = 0;
    size_t len = sNeedle.size();
    size_t replen = sReplace.size();
    std::string input(sHaystack);

    do {
        found = input.find(sNeedle, pos);
        if (found == std::string::npos) {
            break;
        }
        input.replace(found, len, sReplace);
        pos = found + replen;
        ++c;
    } while(!nTimes || c < nTimes);

    return input;
}