C++でアプリケーションを開発している際、CSVデータやログファイルなどのテキストデータを解析するために「文字列を特定の区切り文字で分割したい」という場面は非常に多く訪れます。
std::string 自体には、Pythonの split() や Javaの String.split() といった専用メソッドは用意されていません。そのため、C++エンジニアは用途に合わせて最適な分割ロジックを自分で選択したり実装したりする必要があります。
この記事では、C++における文字列分割の基本手法から、実装が簡潔なstringstreamやgetlineの使い方、そしてモダンなC++20以降での推奨されるrangesライブラリを用いたスマートな実装まで、具体的なサンプルコード付きで徹底解説します。
![]() 執筆者:マヒロ |
|
- OS:Windows 11 / macOS Sequoia
- IDE:Visual Studio / VS Code / IntelliJ IDEA
- その他:Chrome DevTools / 各言語最新安定版
※本メディアでは、上記環境にてコードの動作と情報の正確性を検証済みです。
stringstreamを使ったスペース区切りの文字列分割
C++で最も手軽に、かつ「C++らしく」文字列を分割する方法の一つが、std::stringstream を活用する手法です。
特にスペース(空白)や改行で区切られた文章を単語ごとにバラバラにしたい場合に、非常に簡潔な記述で実現できます。
ここでは、標準的な文字列ストリームを利用した分割の仕組みと、その特性について見ていきましょう。
stringstreamによる基本的な分割コード
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
int main() {
std::string text = "C++ String Split Example";
std::stringstream ss(text);
std::string buffer;
std::vector<std::string> words;
// スペース区切りで一単語ずつ読み込む
while (ss >> buffer) {
words.push_back(buffer);
}
// 結果の出力
for (const auto& word : words) {
std::cout << "[" << word << "]" << std::endl;
}
return 0;
}
実行結果
[C++]
[String]
[Split]
[Example]
まず、std::stringstream オブジェクトを対象の文字列で初期化しています。
これにより、文字列を「入力ストリーム」として、あたかもキーボード入力(std::cin)のように扱うことが可能になります。
while (ss >> buffer) の部分では、ストリーム抽出演算子 >> を使用しています。
この演算子は、デフォルトで空白文字(スペース、タブ、改行)を区切りとして認識し、それまでの文字列を変数 buffer に格納します。
この方法は可読性が高く実装も簡潔ですが、内部でロケール処理やフォーマット解析を行うため、パフォーマンス重視の場面(大量のデータを高速に処理する必要がある場合)では不向きである点に注意が必要です。
getline関数を使った特定の区切り文字での分割
カンマ(,)区切りのCSV形式や、コロン(:)で区切られたデータなど、スペース以外の特定の文字で分割したい場合には std::getline 関数が有効です。
getline は「1行まるごと読み込む関数」として知られていますが、実は第3引数に「区切り文字(デリミタ)」を指定できる設計になっています。
カンマ区切りの文字列を分割するコード例
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
int main() {
std::string csvData = "apple,banana,cherry,orange";
std::stringstream ss(csvData);
std::string buffer;
std::vector<std::string> results;
// 第3引数に区切り文字 ',' を指定
while (std::getline(ss, buffer, ',')) {
results.push_back(buffer);
}
for (const auto& s : results) {
std::cout << "Fruit: " << s << std::endl;
}
return 0;
}
実行結果
Fruit: apple
Fruit: banana
Fruit: cherry
Fruit: orange
この処理の内容を詳しく解説します。
std::getline(ss, buffer, ',') は、ストリーム ss から文字を読み込み、カンマ , が現れるまでの内容を変数 buffer に代入します。
この際、区切り文字として使われたカンマは自動的に読み飛ばされるため、ループを回すだけで次々と要素を抽出できます。
この手法は文字列分割の基本ですが、std::getline は1文字の区切りしか指定できないため、複数種類の区切り文字(例:, と ; の両方)を同時に扱う場合は、事前に置換処理を行うなどの工夫が必要です。
findとsubstrを使った手動での文字列抽出テクニック
「区切り文字が複数文字の文字列である」「特定のパターンを探して分割したい」といった場合には、std::string::find と std::string::substr を組み合わせたアルゴリズムが有効です。
標準機能を組み合わせるため、実装次第では比較的メモリ効率の良い処理が可能です。
手動パースによる文字列分割の実装
#include <iostream>
#include <string>
#include <vector>
int main() {
std::string target = "key:value;id:123";
std::string delimiter = ";";
std::vector<std::string> tokens;
size_t pos = 0;
size_t next_pos;
// 区切り文字 ';' を検索しながらループ
while ((next_pos = target.find(delimiter, pos)) != std::string::npos) {
// 現在の位置から区切り文字までの長さを計算して切り出し
tokens.push_back(target.substr(pos, next_pos - pos));
// 次の検索開始位置を更新(区切り文字の次から)
pos = next_pos + delimiter.length();
}
// 最後の区切り文字より後ろに残った部分を追加
tokens.push_back(target.substr(pos));
for (const auto& t : tokens) {
std::cout << "Token: " << t << std::endl;
}
return 0;
}
実行結果
Token: key:value
Token: id:123
target.find(delimiter, pos) によって、現在の検索開始位置 pos 以降にある最初の区切り文字の場所を探します。
見つかったインデックス next_pos と現在の pos の差分を計算することで、切り出したい部分の長さを算出しています。
そして target.substr(pos, 長さ) を実行して部分文字列を取得し、リストに追加します。
substr は新しい文字列を生成(コピー)するため、より高度な最適化を求める場合は、C++17以降の std::string_view を活用することでコピーコストを抑えた高効率な実装が可能になります。
【モダンC++】ranges::views::split による最新の分割方法
モダンなC++開発において、非常に洗練された記述を可能にするのがC++20で導入されたRangesライブラリです。
これを使うと、これまでループや一時変数で苦労していた文字列分割を、パイプライン(|)を使って宣言的に記述できるようになります。
C++20/23 形式のスマートな分割コード
#include <iostream>
#include <string>
#include <string_view>
#include <ranges>
#include <vector>
int main() {
std::string text = "Learn-Modern-Cpp-Ranges";
// パイプ演算子 | を使って分割ビューを生成
auto split_view = text | std::views::split('-');
std::cout << "分割された要素:" << std::endl;
for (const auto& subrange : split_view) {
// C++23以降であれば std::ranges::to<std::string>() での変換が最も安全かつ推奨
auto s = std::ranges::to<std::string>(subrange);
std::cout << " - " << s << std::endl;
}
return 0;
}
実行結果
分割された要素:
- Learn
- Modern
- Cpp
- Ranges
std::views::split('-') は、元の文字列を実際に分割して新しいメモリを確保するのではなく、「どこで区切るか」という情報を保持した「ビュー(参照)」を生成します。
これを 「遅延評価(Lazy Evaluation)」 と呼びます。
コピーを発生させないため高速になる可能性がありますが、ループ内で std::string や std::string_view に変換する際には注意が必要です。
C++23で導入された std::ranges::to を使うことで、サブレンジから安全に目的の型へ変換できます。
また、C++20環境で string_view を作る場合は、イテレータの性質に配慮した構築が必要です。
最新の規格をフルに活用することで、コードの可読性は飛躍的に向上します。
応用:文字列を「一文字ずつ」操作する際の注意点
特殊なケースとして、区切り文字を使わずに一文字ずつ処理したい場合があります。
1文字ずつ取り出す実装例
#include <iostream>
#include <string>
int main() {
std::string text = "Hello";
// 範囲for文で1バイト(char)ずつ取り出す
for (char c : text) {
std::cout << "Char: " << c << std::endl;
}
return 0;
}
この処理では、文字列を文字の配列(char の集まり)として扱い、先頭から順にアクセスしています。
ただし、UTF-8文字列を扱う場合、1文字が複数バイトになる点に注意が必要です。
日本語などのマルチバイト文字が含まれる場合、char 単位のループでは文字が途中で分断されて正しく表示・判定できません。
日本語を正確に1文字ずつ処理したい場合は、std::u32string への変換や、ICUなどの外部ライブラリ、あるいは各文字のバイト長を判定するロジックを併用するのが実務上の定石です。
C++のスキルを活かして年収を上げる方法
以上、C++での文字列分割の方法について解説しました。
C++を扱えるエンジニアは希少価値が高いため、転職によって数十万円の年収アップはザラで、100万円以上年収が上がることも珍しくありません。
なお、転職によって年収を上げたい場合は、エンジニア専門の転職エージェントサービスを利用するのが最適です。
転職エージェントも副業エージェントも、登録・利用は完全無料なので、どんな求人や副業案件があるのか気になる方は、気軽に利用してみるとよいでしょう。
| 年収アップにこだわりたい方 (平均アップ額138万円の実績) | テックゴー |
| 未経験・経験者問わず幅広く探したい方 | ユニゾンキャリア |
| 業界に精通した担当者に相談したい方 | キッカケエージェント |
| ゲーム業界への転職を志望する方 | ファミキャリ |
| エンジニア未経験からキャリアを築く方 | イーチキャリア |



