C++の文字列クラスstd::stringにおいて文字列や文字、数字を連結/結合する方法を紹介します。
目次
- 文字/文字列の連結
- operator+() 演算子(
+
演算子による連結) - 文字列の連結コストについて
- operator+() 演算子(
- 文字/文字列の結合・追加・挿入
- operator+=() メンバ演算子関数(
+=
演算子による簡潔な結合) - append メンバ関数(文字列の末尾に結合)
- push_back メンバ関数(文字の追加)
- insert メンバ関数(任意の位置に追加)
- 文字列のキャパシティと効率的な文字列結合
- operator+=() メンバ演算子関数(
- stringstream クラスによる連結
- std::to_string 関数による数値の連結・結合
文字/文字列の連結
operator+() 演算子
std::string用のoperator+()
演算子関数で文字列の連結を行うことができます。
std::string a = "a";
std::string b = "b";
std::string c = a + b; // c == "ab" (文字列型同士の連結)
std::string d = a + "d"; // d == "ad" (const char *型との連結)
std::string e = a + 'e'; // e == "ae" (文字型との連結)
+
演算子に対応する値のいずれか一方がstd::string
型であれば、char
型やconst char *
との連結も可能となります。
文字列の連結コストについて
なおoperator+()
演算子関数は演算の度に連結後の新たな文字列を生成します。場合によっては連結ではなく結合を行ったほうが効率的な処理になる場合があります。
/* 連結 - 効率が悪い */
std::string a = "a";
std::string b = a + "b" + "c"; // `a + "b"`の結果(一時オブジェクト)と`"c"`の連結が発生する
/* 結合 - 効率的 */
std::string a = "a";
a += "b"; // 結合先の文字列に直接文字列を追加する
a += "c"; // a == "abc"
std::stringは内部バッファを持つため、可変長文字列として扱うこともできます。Javaの世界で言うところのStringBuilder/StringBufferクラスに相当する役割を担うことができます。+=
演算子やappend
メンバ関数による結合処理、キャパシティの指定方法については次項を参考にしてください。
文字/文字列の結合・追加・挿入
既存の文字列に新たな文字列や文字を追加したい場合にはoperator+=()
メンバ演算子関数やappend
, insert
, push_back
メンバ関数を用います。
std::string s = "a";
s += "b"; // "ab" (文字列の追加) # operator+=() メンバ演算子関数
s.append("c"); // "abc" (文字列の追加) # append メンバ関数
s.push_back('d'); // "abcd" (文字の挿入) # push_back メンバ関数
s.insert(0, "#"); // "#abcd"(先頭に挿入) # insert メンバ関数
operator+=() メンバ演算子関数
+=
演算子でstd:string型のオブジェクトに対して新たな文字列や文字を結合することができます。
std::string s = "a";
s += "b"; // "ab" (const char*型の文字列を追加)
s += 'c'; // "abc" (char型の文字を挿入)
s += std::string("d"); // "abcd" (std::string型の文字列を追加)
なお+=
は次に紹介するappend
, push_back
メンバ関数による追加処理と同等の働きをします。
inline string& operator+=(const string& s) { return append(s); }
inline string& operator+=(const char* s) { return append(s); }
inline string& operator+=(char c) { return push_back(c), *this; }
append メンバ関数
append
メンバ関数で呼び出し元のオブジェクトに新たな文字列や文字を追加することができます。
std::string s = "a";
s.append("b"); // "ab" (const char *型の文字列を追加)
s.append(1, 'c'); // "abc" (③ char型の文字を一文字分挿入)
s.append(std::string("d")); // "abcd" (std::string型の文字列を追加)
std::string t = "";
t.append("abc", 2); // "ab" (① 2文字分挿入)
t.append("ABC", 1, 2); // "abBC"(② 1文字目以降の位置から2文字分挿入)
① 第二引数に、挿入したい文字列の長さを指定することもできます。② 文字列の一部を切り出して挿入したい場合には、第二引数に開始位置、第三引数に長さを指定します。③ 文字型を挿入する場合には第一引数に文字の挿入回数を指定する必要があります(一文字だけ追加する場合には後に紹介するpush_backメンバ関数の利用が最適です)。
push_back メンバ関数
文字型の値を挿入する場合には上記のメンバ関数に加えてpush_back
メンバ関数を用いることができます。
std::string s = "a";
s.push_back('b'); // s == "ab"
s += 'c'; // `push_back('c')`と同等の処理が行われる
insert メンバ関数
insert
メンバ関数を用いることで、文字列の先頭や指定の位置に新たな文字列や文字を挿入することができます。
std::string s = "c";
s.insert(0, "a"); // "ac" (先頭に追加)
s.insert(1, "b"); // "abc" (1文字目以降に追加)
s.insert(s.end(), 'e'); // "abce" (末尾に挿入)
s.insert(s.end() - 1, 'd'); // "abcde"(末尾の1つ前に挿入)
s.insert(s.end(), {'f', 'g'}); // "abcdefg"
std::string t = "";
t.insert(0, "abc", 2); // "ab" (2文字分挿入)
t.insert(0, "ABC", 1, 2); // "BCab"(1文字目以降の位置から2文字分挿入)
第一引数には挿入位置を指定します。文字列挿入時には数値、文字挿入時にはイテレータを指定することができます。
文字列のキャパシティと効率的な文字列結合
std::string型のオブジェクトに文字列を追加するとバッファ(メモリ)の再確保が発生する場合があるため注意が必要です。複数の文字列や文字を連続して追加する場合には、事前にバッファの容量(キャパシティ)を指定しておくことが有効です。
std::stringではreserve
メンバ関数で可変長文字列のキャパシティを指定することができます。なおcapacity
メンバ関数は現在のキャパシティを取得するための機能です。
std::string s = "1234567890123456";
s.capacity(); // 22 (現在のキャパシティ)
// 22文字分のバッファが確保されている
// 23文字以上の結合が行われるとバッファの再確保が発生してしまう
s.reserve(64); // キャパシティを事前に増やしておく
s.capacity(); // 64 (変更後のキャパシティ)
s += s; // バッファの再確保が発生しない
s += s; // バッファの再確保が発生しない
s.capacity(); // 64 (キャパシティは増大しない)
キャパシティを調整しない場合には、キャパシティを超えた文字列結合が行われる度にバッファの再確保が発生してしまいます。
std::string s = "1234567890123456";
s += s; // バッファの再確保が発生(`s.capacity()`は47に増大)
s += s; // バッファの再確保が発生(`s.capacity()`は95に増大)
再確保時には大きめのバッファ容量が確保される場合があり、reserveメンバ関数で事前にキャパシティを確保した際よりも大きなメモリを消費することになるため注意が必要です。結合後の文字列長が事前に分かっている場合には、予めキャパシティを指定しておくようにすると効率的で無駄のない文字列結合を実現できます。
stringstream クラスによる連結
文字列ストリームクラスstd::stringstream
を用いれば、文字列/文字/数値を一括で処理することもできます。
// #include <sstream>
std::stringstream ss;
ss << "Shop" << ' ' << 99 << std::string("\n");
std::string s = ss.str(); // s == "Shop 99\n"
std::cout
等の入出力ストリームと同等の扱いが可能であり、複雑なフォーマットを行う際にも便利です。
std::to_string 関数による数値の連結・結合
文字列に整数型や浮動小数点数型の数値を追加する場合には、一度std::to_string
関数で数値を文字列に変換した上で連結や結合を行う必要があります。先程紹介した+
, +=
演算子やappend
, push_back
メンバ関数では、数値を直接追加することはできないため注意が必要です。
std::string s = "s";
s += 99; // "sc"(99がchar型に変換されるため → 99 == 'c')
s += std::to_string(99); // "sc99"(数値を数字に変換した上で追加する)
// 数値との連結にも対応していない
std::string s = "s";
std::string t = s + 9; // error: invalid operands to binary expression ('std::string' (aka 'basic_string<char, char_traits<char>, allocator<char> >') and 'int')
std::string t = s + std::to_string(9); // OK