Как заменить подстроку в строке на другую подстроку в С++, какие функции я мог бы использовать?
eg: string test = "abc def abc def";
test.replace("abc", "hij").replace("def", "klm"); //replace occurrence of abc and def with other substring
Как заменить подстроку в строке на другую подстроку в С++, какие функции я мог бы использовать?
eg: string test = "abc def abc def";
test.replace("abc", "hij").replace("def", "klm"); //replace occurrence of abc and def with other substring
В С++ нет встроенной функции для этого. Если вы хотите заменить все экземпляры одной подстроки на другую, вы можете сделать это, смешивая вызовы с string::find
и string::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
на длину строки, которая была вставлена в строку. В этом конкретном примере - заменяя "abc"
на "def"
- это на самом деле не требуется. Однако в более общей настройке важно пропустить строку, которая только что была заменена. Например, если вы хотите заменить "abc"
на "abcabc"
, не перескакивая по вновь замененному сегменту строки, этот код будет постоянно заменять части вновь замененных строк до тех пор, пока память не будет исчерпана. Независимо от этого, может быть, немного быстрее пропустить эти новые символы, так как это позволяет сэкономить время и усилия с помощью функции string::find
.
Надеюсь, это поможет!
Ускорить библиотеку алгоритмов строк:
#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"
);
}
Я думаю, что все решения потерпят неудачу, если длина заменяющей строки отличается от длины строки, подлежащей замене. (найдите "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 );
}
}
В С++ 11 вы можете использовать regex_replace
:
string test = "abc def abc def";
test = regex_replace(test, regex("def"), "klm");
str.replace(str.find(str2),str2.length(),str3);
Где
str
- это базовая строкаstr2
является подстрокой, чтобы найтиstr3
является заменой подстрокиЗамена подстрок не должна быть такой трудной.
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
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")
Если вы уверены, что требуемая подстрока присутствует в строке, это заменит первое появление "abc"
на "hij"
test.replace( test.find("abc"), 3, "hij");
Он потерпит крах, если у вас нет теста "abc" в тесте, поэтому используйте его с осторожностью.
Обобщая ответ rotmax, вот полное решение для поиска и замены всех экземпляров в строке. Если обе подстроки имеют разный размер, подстрока заменяется с помощью string:: erase и string:: insert., В противном случае используется более быстрая строка:: replace.
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 );
}
}
}
Вот решение, которое я написал, используя тактику строителя:
#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);
}
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;
}
Я думаю, что это соответствует вашему требованию с небольшим кодом!
импозантная версия @Czarek Tomczak.
разрешить как std::string
, так и std::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::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 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;
size_t index = 0;
std::string str = "T X T", substr1=" " /*To replace*/, substr2="-" /*replace with this*/;
for (index = str.find(substr1, index); index != std::string::npos; index = str.find(substr1, index + strlen(substr1.c_str())) )
str.replace(index, strlen(substr1.c_str()), substr2);