用另一个子字符串 C + + 替换子字符串

如何用 C + + 中的另一个子字符串替换字符串中的一个子字符串,可以使用哪些函数?

eg: string test = "abc def abc def";
test.replace("abc", "hij").replace("def", "klm"); //replace occurrence of abc and def with other substring
238845 次浏览

在 C + + 中没有一个内置函数可以做到这一点。如果希望用另一个子字符串替换一个子字符串的所有实例,可以通过混合调用 string::findstring::replace来实现。例如:

size_t index = 0;
while (true) {
/* Locate the substring to replace. */
index = str.find("abc", index);
if (index == std::string::npos) break;


/* Make the replacement. */
str.replace(index, 3, "def");


/* Advance index forward so the next iteration doesn't pick it up as well. */
index += 3;
}

在这段代码的最后一行中,我将 index增加到插入到字符串中的字符串的长度。在这个特殊的例子中-用 "def"代替 "abc"-这实际上是不必要的。但是,在更一般的设置中,跳过刚被替换的字符串非常重要。例如,如果您想用 "abcabc"替换 "abc",而不跳过新替换的字符串段,这段代码将不断地替换新替换的字符串的一部分,直到内存耗尽。无论如何,跳过这些新字符可能会稍微快一些,因为这样做可以节省 string::find函数的一些时间和精力。

希望这个能帮上忙!

如果您确定字符串中存在所需的子字符串,那么这将替换 "abc""hij"的第一次出现

test.replace( test.find("abc"), 3, "hij");

如果你在测试中没有“ abc”,它会崩溃,所以要小心使用它。

using std::string;


string string_replace( string src, string const& target, string const& repl)
{
// handle error situations/trivial cases


if (target.length() == 0) {
// searching for a match to the empty string will result in
//  an infinite loop
//  it might make sense to throw an exception for this case
return src;
}


if (src.length() == 0) {
return src;  // nothing to match against
}


size_t idx = 0;


for (;;) {
idx = src.find( target, idx);
if (idx == string::npos)  break;


src.replace( idx, target.length(), repl);
idx += repl.length();
}


return src;
}

因为它不是 string类的成员,所以它的语法不像您的示例那样好,但是下面的代码可以实现相同的功能:

test = string_replace( string_replace( test, "abc", "hij"), "def", "klm")
    string & replace(string & subj, string old, string neu)
{
size_t uiui = subj.find(old);
if (uiui != string::npos)
{
subj.erase(uiui, old.size());
subj.insert(uiui, neu);
}
return subj;
}

我认为这符合您的需求与少量代码!

Boost String 算法库 方法:

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


{ // 1.
string test = "abc def abc def";
boost::replace_all(test, "abc", "hij");
boost::replace_all(test, "def", "klm");
}




{ // 2.
string test = boost::replace_all_copy
(  boost::replace_all_copy<string>("abc def abc def", "abc", "hij")
,  "def"
,  "klm"
);
}

替换子字符串应该没有那么难。

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 changed: "
<< 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

我认为,如果替换字符串的长度与要替换的字符串的长度不同,那么所有的解决方案都将失败。(搜索“ abc”并用“ xxxxxx”替换) 一般的做法可能是:

void replaceAll( string &s, const string &search, const string &replace ) {
for( size_t pos = 0; ; pos += replace.length() ) {
// Locate the substring to replace
pos = s.find( search, pos );
if( pos == string::npos ) break;
// Replace by erasing and inserting
s.erase( pos, search.length() );
s.insert( pos, replace );
}
}

通过对 rotmax 的回答进行推广,这里提供了一个搜索和替换字符串中所有实例的完整解决方案。如果两个子字符串的大小不同,则使用 string: : delete 和 string: : insert. 替换子字符串,否则使用更快的 string: : place。

void FindReplace(string& line, string& oldString, string& newString) {
const size_t oldSize = oldString.length();


// do nothing if line is shorter than the string to find
if( oldSize > line.length() ) return;


const size_t newSize = newString.length();
for( size_t pos = 0; ; pos += newSize ) {
// Locate the substring to replace
pos = line.find( oldString, pos );
if( pos == string::npos ) return;
if( oldSize == newSize ) {
// if they're same size, use std::string::replace
line.replace( pos, oldSize, newString );
} else {
// if not same size, replace by erasing and inserting
line.erase( pos, oldSize );
line.insert( pos, newString );
}
}
}
str.replace(str.find(str2),str2.length(),str3);

在哪里

  • str是基本字符串
  • str2是要查找的子字符串
  • str3是替换子字符串

改进版由@柴克 · 托姆恰克。
允许同时使用 std::stringstd::wstring

template <typename charType>
void ReplaceSubstring(std::basic_string<charType>& subject,
const std::basic_string<charType>& search,
const std::basic_string<charType>& replace)
{
if (search.empty()) { return; }
typename std::basic_string<charType>::size_type pos = 0;
while((pos = subject.find(search, pos)) != std::basic_string<charType>::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
}

中,你可以使用 std::regex_replace:

#include <string>
#include <regex>


std::string test = "abc def abc def";
test = std::regex_replace(test, std::regex("def"), "klm"); // replace 'def' -> 'klm'
// test = "abc klm abc klm"
std::string replace(const std::string & in
, const std::string & from
, const std::string & to){
if(from.size() == 0 ) return in;
std::string out = "";
std::string tmp = "";
for(int i = 0, ii = -1; i < in.size(); ++i) {
// change ii
if     ( ii <  0 &&  from[0] == in[i] )  {
ii  = 0;
tmp = from[0];
} else if( ii >= 0 && ii < from.size()-1 )  {
ii ++ ;
tmp = tmp + in[i];
if(from[ii] == in[i]) {
} else {
out = out + tmp;
tmp = "";
ii = -1;
}
} else {
out = out + in[i];
}
if( tmp == from ) {
out = out + to;
tmp = "";
ii = -1;
}
}
return out;
};

下面是一个使用递归的解决方案,它将子字符串的所有匹配项替换为另一个子字符串。无论字符串的大小如何,这都是可行的。

std::string ReplaceString(const std::string source_string, const std::string old_substring, const std::string new_substring)
{
// Can't replace nothing.
if (old_substring.empty())
return source_string;


// Find the first occurrence of the substring we want to replace.
size_t substring_position = source_string.find(old_substring);


// If not found, there is nothing to replace.
if (substring_position == std::string::npos)
return source_string;


// Return the part of the source string until the first occurance of the old substring + the new replacement substring + the result of the same function on the remainder.
return source_string.substr(0,substring_position) + new_substring + ReplaceString(source_string.substr(substring_position + old_substring.length(),source_string.length() - (substring_position + old_substring.length())), old_substring, new_substring);
}

用法例子:

std::string my_cpp_string = "This string is unmodified. You heard me right, it's unmodified.";
std::cout << "The original C++ string is:\n" << my_cpp_string << std::endl;
my_cpp_string = ReplaceString(my_cpp_string, "unmodified", "modified");
std::cout << "The final C++ string is:\n" << my_cpp_string << std::endl;

下面是我使用构建器策略编写的一个解决方案:

#include <string>
#include <sstream>


using std::string;
using std::stringstream;


string stringReplace (const string& source,
const string& toReplace,
const string& replaceWith)
{
size_t pos = 0;
size_t cursor = 0;
int repLen = toReplace.length();
stringstream builder;


do
{
pos = source.find(toReplace, cursor);


if (string::npos != pos)
{
//copy up to the match, then append the replacement
builder << source.substr(cursor, pos - cursor);
builder << replaceWith;


// skip past the match
cursor = pos + repLen;
}
}
while (string::npos != pos);


//copy the remainder
builder << source.substr(cursor);


return (builder.str());
}

测试:

void addTestResult (const string&& testId, bool pass)
{
...
}


void testStringReplace()
{
string source = "123456789012345678901234567890";
string toReplace = "567";
string replaceWith = "abcd";
string result = stringReplace (source, toReplace, replaceWith);
string expected = "1234abcd8901234abcd8901234abcd890";


bool pass = (0 == result.compare(expected));
addTestResult("567", pass);




source = "123456789012345678901234567890";
toReplace = "123";
replaceWith = "-";
result = stringReplace(source, toReplace, replaceWith);
expected = "-4567890-4567890-4567890";


pass = (0 == result.compare(expected));
addTestResult("start", pass);




source = "123456789012345678901234567890";
toReplace = "0";
replaceWith = "";
result = stringReplace(source, toReplace, replaceWith);
expected = "123456789123456789123456789";


pass = (0 == result.compare(expected));
addTestResult("end", pass);




source = "123123456789012345678901234567890";
toReplace = "123";
replaceWith = "-";
result = stringReplace(source, toReplace, replaceWith);
expected = "--4567890-4567890-4567890";


pass = (0 == result.compare(expected));
addTestResult("concat", pass);




source = "1232323323123456789012345678901234567890";
toReplace = "323";
replaceWith = "-";
result = stringReplace(source, toReplace, replaceWith);
expected = "12-23-123456789012345678901234567890";


pass = (0 == result.compare(expected));
addTestResult("interleaved", pass);






source = "1232323323123456789012345678901234567890";
toReplace = "===";
replaceWith = "-";
result = utils_stringReplace(source, toReplace, replaceWith);
expected = source;


pass = (0 == result.compare(expected));
addTestResult("no match", pass);


}
std::string replace(std::string str, std::string substr1, std::string substr2)
{
for (size_t index = str.find(substr1, 0); index != std::string::npos && substr1.length(); index = str.find(substr1, index + substr2.length() ) )
str.replace(index, substr1.length(), substr2);
return str;
}

简短的解决方案,您不需要任何额外的库。

std::string replace(std::string str, const std::string& sub1, const std::string& sub2)
{
if (sub1.empty())
return str;


std::size_t pos;
while ((pos = str.find(sub1)) != std::string::npos)
str.replace(pos, sub1.size(), sub2);


return str;
}
#include <string>

第一:

void replace_first(std::string& text, const std::string& from,
const std::string& to)
{
const auto at = text.find(from, 0);


if (at != std::string::npos)
text.replace(at, from.length(), to);
}

所有人:

void replace_all(std::string& text, const std::string& from,
const std::string& to)
{
for (auto at = text.find(from, 0); at != std::string::npos;
at = text.find(from, at + to.length()))
{
text.replace(at, from.length(), to);
}
}

数:

size_t replace_count(std::string& text,
const std::string& from, const std::string& to)
{
size_t count = 0;


for (auto at = text.find(from, 0); at != std::string::npos;
at = text.find(from, at + to.length()))
{
++count;
text.replace(at, from.length(), to);
}


return count;
}

收到:

std::string replace_all_copy(const std::string& text,
const std::string& from, const std::string& to)
{
auto copy = text;
replace_all(copy, from, to);
return copy;
}

我认为这是 最短的的解决方案。 它将取代所有的 绝对的Abc

 string test = "abc def abc def";
regex p("def");
cout<<regex_replace(test, p, "abc")<<endl;