文字列の部分文字列をC++の別の部分文字列に置き換えるにはどうすればよいですか、どの関数を使用できますか
eg: string test = "abc def abc def";
test.replace("abc", "hij").replace("def", "klm"); //replace occurrence of abc and def with other substring
これを行うC++の組み込み関数はありません。ある部分文字列のすべてのインスタンスを別の部分文字列に置き換えたい場合は、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 );
}
}
C++ 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")
Rotmaxの答えを一般化して、文字列内のすべてのインスタンスを検索および置換する完全なソリューションを以下に示します。両方のサブストリングのサイズが異なる場合、サブストリングはstring :: eraseおよびstring :: insertを使用して置き換えられます。それ以外の場合は、高速のstring :: 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 );
}
}
}
必要な部分文字列が文字列に存在することが確実な場合、最初の"abc"
を"hij"
に置き換えます
test.replace( test.find("abc"), 3, "hij");
テストに「abc」がないとクラッシュしますので、注意して使用してください。
ビルダーの戦術を使用して作成したソリューションを次に示します。
#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);
}
@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();
}
}
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;
}
私はこれがいくつかのコードであなたの要件に合うと思います!
これは、部分文字列のすべての出現を別の部分文字列で置き換える再帰を使用したソリューションです。これは、文字列のサイズに関係なく機能します。
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;
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;
};
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);