std::string文字列型の一部を指定の文字や文字列で置き換える方法を解説します。string型のreplaceメンバ関数は検索文字列による置換には対応していないため、置換範囲を手動で指定する必要があります。
std::string s = "a-b";
// 範囲指定による置換
s.replace(1, 2, "="); // s == "a=b" (※文字列自身が書き換わる)
// 検索文字列と置換文字列による置換には非対応
s.replace("-", "="); // error: no matching member function for call to 'replace'
実際に検索文字列による置換/全置換を実現する際には、find
メンバ関数による文字列出現位置の検索や、繰り返し文による置換処理が必要となります。次項以降の解説を参考にしてください。
目次
- replaceメンバ関数(基本的な仕様と諸注意)
- 文字列の置換(replace_first 相当)
- 文字列の全置換(replace_all 相当)
- std::replace関数による全置換(char型による一文字置換)
- findメンバ関数による全置換(繰り返し文による手動置換)
- replace関数の自作方法(置換/全置換に対応した万能関数)
replaceメンバ関数
std::string型のreplaceメンバ関数は自身の文字列の特定の範囲を指定の文字列で置き換える機能です。
replaceメンバ関数の第一引数には置き換えの開始位置を指定します。第二引数には置き換えたい長さを指定します。第三引数には置き換え後の新たな文字列を指定します。戻り値は自身のオブジェクトの参照です。
std::string s = "abcd";
s.replace(1, 2, "-"); // s == "a-d"
s.replace(0, 1, 1, 'A'); // s == "A-d"
s.replace(0, 1, 2, '*'); // s == "**-d"
s.replace(s.begin() + 2, s.end(), "#");
// s == "**#"
イテレータによる範囲指定も可能です。置換文字が文字型の値の場合には、置換文字を第四引数に指定する必要があります。その際、第三引数には文字を埋める回数を指定します。replaceは破壊的メソッドであり、自身のオブジェクトの値を変更する点に注意してください。
文字列の置換
最初に一致した文字列を置換する場合には、findメンバ関数による検索結果を活用する必要があります。findは検索文字列の出現位置を返す関数です。
/// "a, b".replaceFirst(", ", "|") 相当の文字列置換
std::string s = "a, b";
std::string t = ", "; // 検索文字列
auto pos = s.find(t); // 検索文字列が見つかった位置 (pos == 1)
auto len = t.length(); // 検索文字列の長さ (len == 2)
if (pos != std::string::npos) {
s.replace(pos, len, "|"); // s == "a|b"
}
findメンバ関数はオーバロードに対応しているため、std::string型の文字列以外にも文字型(char
)の値やC言語スタイルの文字列(const char*
)を検索することも可能です。
文字列の全置換
一致した全ての文字列を置換する方法です。
std::replace関数による全置換
文字型の値同士の置換であればstd::replace
関数を用いることができます。replace関数はchar型等による一文字単位での置換にのみ対応しています。
// #include <algorithm> // std::replace
std::string s = "a-b-c";
std::replace(s.begin(), s.end(), '-', '=');
// s == "a=b=c"
findメンバ関数による全置換
「# 文字列の置換」で紹介した置換処理を、検索文字列が出現しなくなるまで繰り返し行う方法です。
std::string s = "a, b, c"; // 置換対象の文字列
std::string target = ", "; // 検索文字列
std::string replacement = "-"; // 置換文字列
if (!target.empty()) {
std::string::size_type pos = 0;
while ((pos = s.find(target, pos)) != std::string::npos) {
s.replace(pos, target.length(), replacement);
pos += replacement.length();
}
}
// s == "a-b-c"
replace関数の自作方法
置換と全置換に対応したreplace関数の実装例です。デフォルトでは全置換が行われます。第三引数のreplace_firstがtrueに指定された場合には、最初にマッチした文字列のみが置換されます。
assert( "a b c" == replace("a-b-c", "-", " ") ); // 全置換
assert( "a b-c" == replace("a-b-c", "-", " ", true) ); // 置換
assert( "ab" == replace("ab", "", "-") );
assert( "-a-b-" == replace("ab", "", "-", false, true) );
検索文字列が空文字の場合には元の文字列をそのまま返します。ただしreplace_emptyがtrueに指定された場合は置換文字列を文字列シーケンスの区切り文字として挿入します(ruby: "ab".gsub("", "-") == "-a-b-"
に相当)。
元の文字列を直接変更したい場合には、戻り値型と第一引数の型を参照型のstd::string&
に書き換えます。
template<class T, class U> std::string replace(std::string s, const T& target, const U& replacement, bool replace_first = 0, bool replace_empty = 0) {
using S = std::string;
using C = std::string::value_type;
using N = std::string::size_type;
struct {
auto len(const S& s) { return s.size(); }
auto len(const C* p) { return std::char_traits<C>::length(p); }
auto len(const C c) { return 1; }
auto sub(S* s, const S& t, N pos, N len) { s->replace(pos, len, t); }
auto sub(S* s, const C* t, N pos, N len) { s->replace(pos, len, t); }
auto sub(S* s, const C t, N pos, N len) { s->replace(pos, len, 1, t); }
auto ins(S* s, const S& t, N pos) { s->insert(pos, t); }
auto ins(S* s, const C* t, N pos) { s->insert(pos, t); }
auto ins(S* s, const C t, N pos) { s->insert(pos, 1, t); }
} util;
N target_length = util.len(target);
N replacement_length = util.len(replacement);
if (target_length == 0) {
if (!replace_empty || replacement_length == 0) return s;
N n = s.size() + replacement_length * (1 + s.size());
s.reserve(!replace_first ? n: s.size() + replacement_length );
for (N i = 0; i < n; i += 1 + replacement_length ) {
util.ins(&s, replacement, i);
if (replace_first) break;
}
return s;
}
N pos = 0;
while ((pos = s.find(target, pos)) != std::string::npos) {
util.sub(&s, replacement, pos, target_length);
if (replace_first) return s;
pos += replacement_length;
}
return s;
}