2010-08-05 299 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"; 

} 
相關問題