2010-08-05 255 views
141

C++中是否可以用另一个字符串替换部分字符串?用另一个字符串替换字符串的一部分

基本上,我想这样做:

QString string("hello $name"); 
string.replace("$name", "Somename"); 

但我想用C++标准库。

+0

可能重复【什么是用C来代替字符串函数?(http://stackoverflow.com/questions/779875/what-is-the-function-to-replace-string-in- c) - 哎呀对不起,这是C,而不是C++;我希望我能解开。 – polygenelubricants 2010-08-05 19:10:27

+2

为什么有一个'C'标签? – sbi 2010-08-05 19:14:03

+1

@poly我认为这一定也被要求提供C++,但我找不到它 – 2010-08-05 19:15:06

回答

219

有一个函数来查找字符串(find)内的子串,和功能上与另一个字符串(replace)的字符串替换特定的范围内,所以可以结合使用这些得到你想要的效果:

bool replace(std::string& str, const std::string& from, const std::string& to) { 
    size_t start_pos = str.find(from); 
    if(start_pos == std::string::npos) 
     return false; 
    str.replace(start_pos, from.length(), to); 
    return true; 
} 

std::string string("hello $name"); 
replace(string, "$name", "Somename"); 

在回应评论,我觉得replaceAll可能会是这个样子:

void replaceAll(std::string& str, const std::string& from, const std::string& to) { 
    if(from.empty()) 
     return; 
    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(); // In case 'to' contains 'from', like replacing 'x' with 'yx' 
    } 
} 
+2

如果原始字符串中有多个“$ name”实例并且我想要替换所有这些实例,我将如何修复它。 – 2010-08-05 19:14:10

+1

为什么每个'const'参考都不会传递'from'和'to'?你的函数如果'from'不在那里?从我那里得到'-1'。 – sbi 2010-08-05 19:15:53

+0

添加一个循环并使用find()方法的“pos”参数 – 2010-08-05 19:17:08

14

std::string有一个replace方法,是你在找什么?

你可以尝试:

s.replace(s.find("$name"), sizeof("Somename")-1, "Somename"); 

我还没有尝试过自己,只是阅读文档上find()replace()

+0

从我所看到的std :: string替换方法并不需要两个字符串,因为我愿意。 – 2010-08-05 19:10:04

+0

我认为迈克尔Mrozek有一个更优雅的解决方案 – 2010-08-05 19:16:19

+1

这不适合我。 sizeof应该用字符串(“Somename”)替换。size() - 1 – TimZaman 2014-04-10 08:34:09

6

是的,你可以做到这一点,但你必须找到字符串的find()成员的第一个字符串的位置,然后替换它的replace()成员。

string s("hello $name"); 
size_type pos = s.find("$name"); 
if (pos != string::npos) { 
    s.replace(pos, 5, "somename"); // 5 = length($name) 
} 

如果您在使用标准库的规划,你应该得到的书The C++ Standard Library覆盖所有这些东西很好的副本保持。

+0

好吧,我会尝试写我自己的功能来做到这一点。 – 2010-08-05 19:11:02

+1

它是size_t而不是size_type – revo 2013-01-08 23:54:41

+0

它是std :: string :: size_type,而不是size_t或未经修改的size_type。 – jmucchiello 2013-05-18 16:33:55

7

有了新的字符串返回使用本:

std::string ReplaceString(std::string subject, const std::string& search, 
          const std::string& replace) { 
    size_t pos = 0; 
    while ((pos = subject.find(search, pos)) != std::string::npos) { 
     subject.replace(pos, search.length(), replace); 
     pos += replace.length(); 
    } 
    return subject; 
} 

如果您需要的性能,这里是一个优化的函数,修改输入的字符串,它不建立一个字符串的副本:

void ReplaceStringInPlace(std::string& subject, const std::string& search, 
          const std::string& replace) { 
    size_t pos = 0; 
    while ((pos = subject.find(search, pos)) != std::string::npos) { 
     subject.replace(pos, search.length(), replace); 
     pos += replace.length(); 
    } 
} 

测试:

std::string input = "abc abc def"; 
std::cout << "Input string: " << input << std::endl; 

std::cout << "ReplaceString() return value: " 
      << ReplaceString(input, "bc", "!!") << std::endl; 
std::cout << "ReplaceString() input string not modified: " 
      << input << std::endl; 

ReplaceStringInPlace(input, "bc", "??"); 
std::cout << "ReplaceStringInPlace() input string modified: " 
      << input << std::endl; 

输出:

Input string: abc abc def 
ReplaceString() return value: a!! a!! def 
ReplaceString() input string not modified: abc abc def 
ReplaceStringInPlace() input string modified: a?? a?? def 
+0

您对ReplaceStringInPlace()中的subject.replace的调用是真正修改字符串inplace吗? – Damian 2016-07-13 09:08:26

+0

我简单地看了一下源代码,看起来它使用移动语义将旧字符串的前面移动到位,这样就不会被复制,但是新插入的内容会被复制到旧字符串中,而旧的尾部字符串被复制到缓冲的旧字符串的大小调整。有可能字符串扩展得太多,整个底层缓冲区被重新分配,但是如果你像在他的例子中一样替换1到1,我认为它确实发生了“就地”,或者没有任何复制,但是如果你扩展字符串,只有旧字符串的第一部分不会被复制,只有可能那么。 – Motes 2016-10-13 21:38:09

2
std::string replace(std::string base, const std::string from, const std::string to) { 
    std::string SecureCopy = base; 

    for (size_t start_pos = SecureCopy.find(from); start_pos != std::string::npos; start_pos = SecureCopy.find(from,start_pos)) 
    { 
     SecureCopy.replace(start_pos, from.length(), to); 
    } 

    return SecureCopy; 
} 
+2

你能解释一下这段代码吗(在你的答案中)?你可能会得到更多的赞扬! – 2014-04-17 15:04:52

1

我一般这样使用:

std::string& replace(std::string& s, const std::string& from, const std::string& to) 
{ 
    if(!from.empty()) 
     for(size_t pos = 0; (pos = s.find(from, pos)) != std::string::npos; pos += to.size()) 
      s.replace(pos, from.size(), to); 
    return s; 
} 

它反复调用std::string::find()找到搜索字符串的其他事件,直到std::string::find()没有发现任何东西。由于std::string::find()返回匹配的位置,所以我们没有使迭代器无效的问题。

+0

你的replace()函数完美工作。但是如果**的变量**是空的,它会进入无限循环。 std :: string a(“Hello”);替换(a,“”,“world”); – Hill 2015-06-20 11:53:37

+0

@Hill感谢您发现!我以为'std :: string :: find'会返回'npos',如果你没有给它任何东西来找,但显然不是!固定。 – Galik 2015-06-20 12:30:10

51

用C++ 11可以使用std::regex像这样:需要转义转义字符

std::string string("hello $name"); 
    string = std::regex_replace(string, std::regex("\\$name"), "Somename"); 

双反斜线。

+0

我很确定'std :: regex_replace'不接受Qt的字符串。 – BartoszKP 2015-07-23 19:06:46

+1

你说得对。正如它发生的那样,QString提供了一种接受QRexExp的替换方法,允许使用Qt自己的东西。但我认为当前的答案可以通过用'string.toStdString()'替换'string'来解决。 – Tom 2015-07-24 22:36:30

+1

或者只是将'String'改为'std :: string',因为这个问题与Qt无关。请考虑这样做 - 我很乐意在之后提供您的答案。 – BartoszKP 2015-07-25 10:07:33

4

这听起来像一个选项

string.replace(string.find("%s"), string("%s").size(), "Something");

你可以在一个函数包装这个但这一行的解决方案听起来可以接受的。 问题是,这只会改变第一次发生,您可能想循环使用它,但它也允许您使用相同的标记将多个变量插入到此字符串中(%s

+0

喜欢的风格,但发现不同的字符串混淆^^'str.replace(str.find(“%s”),string(“%s”)。size(),“Something”);'' – 2017-04-23 14:18:19

0

我刚刚正在学习C++,但编辑以前发布的一些代码,我可能会使用这样的东西。这使您可以灵活地替换1个或多个实例,还可以指定起点。

using namespace std; 

// returns number of replacements made in string 
long strReplace(string& str, const string& from, const string& to, size_t start = 0, long count = -1) { 
    if (from.empty()) return 0; 

    size_t startpos = str.find(from, start); 
    long replaceCount = 0; 

    while (startpos != string::npos){ 
     str.replace(startpos, from.length(), to); 
     startpos += to.length(); 
     replaceCount++; 

     if (count > 0 && replaceCount >= count) break; 
     startpos = str.find(from, startpos); 
    } 

    return replaceCount; 
} 
0
wstring myString = L"Hello $$ this is an example. By $$."; 
wstring search = L"$$"; 
wstring replace = L"Tom"; 
for (int i = myString.find(search); i >= 0; i = myString.find(search)) 
    myString.replace(i, search.size(), replace); 
3

如果所有字符串的std :: string,你如果使用sizeof(),因为它意味着C字符串,而不是C++字符串发现奇怪的问题与字符的截止。修复方法是使用std::string.size()类方法。

sHaystack.replace(sHaystack.find(sNeedle), sNeedle.size(), sReplace); 

这取代了sHaystack内联 - 没有必要做一个=分配回来。

用法示例:

std::string sHaystack = "This is %XXX% test."; 
std::string sNeedle = "%XXX%"; 
std::string sReplace = "my special"; 
sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace); 
std::cout << sHaystack << std::endl; 
1

如果你想迅速做到这一点,你可以用两个扫描方法。 伪代码:

  1. 第一次解析。找到多少匹配的字符。
  2. 展开字符串的长度。
  3. 秒解析。当我们得到一个我们替换的匹配时,从字符串的末尾开始,否则我们只复制第一个字符串中的字符。

我不确定这是否可以优化到就地算法。

和一个C++ 11代码示例,但我只搜索一个字符。的

#include <string> 
#include <iostream> 
#include <algorithm> 
using namespace std; 

void ReplaceString(string& subject, char search, const string& replace) 
{ 
    size_t initSize = subject.size(); 
    int count = 0; 
    for (auto c : subject) { 
     if (c == search) ++count; 
    } 

    size_t idx = subject.size()-1 + count * replace.size()-1; 
    subject.resize(idx + 1, '\0'); 

    string reverseReplace{ replace }; 
    reverse(reverseReplace.begin(), reverseReplace.end()); 

    char *end_ptr = &subject[initSize - 1]; 
    while (end_ptr >= &subject[0]) 
    { 
     if (*end_ptr == search) { 
      for (auto c : reverseReplace) { 
       subject[idx - 1] = c; 
       --idx;    
      }   
     } 
     else { 
      subject[idx - 1] = *end_ptr; 
      --idx; 
     } 
     --end_ptr; 
    } 
} 

int main() 
{ 
    string s{ "Mr John Smith" }; 
    ReplaceString(s, ' ', "%20"); 
    cout << s << "\n"; 

} 
相关问题