C++ で文字列をデリミタで分割する (文字列パース)
C++ では、文字列を指定した区切り文字 (デリミタ) で分割する機能は標準ライブラリに直接含まれていませんが、いくつかの方法で実現できます。ここでは、std::stringstream
や std::getline
を使った一般的な手法を紹介します。
コード例
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
std::vector<std::string> split(const std::string& s, char delim ) {
std::istringstream iss(s);
std::string item;
std::vector<std::string> elems;
while (std::getline(iss, item, delim )) {
elems.push_back(item);
}
return elems;
}
int main() {
std::string str = "apple,banana,orange";
char delim = ',';
std::vector<std::string> result = split(str, delim);
for (const std::string& word : result) {
std::cout << word << std::endl;
}
return 0;
}
コードの説明
- ヘッダファイルのインクルード:
iostream
,string
,sstream
,vector
をインクルードします。 split
関数の定義:std::string
型の入力文字列s
と、char
型のデリミタdelim
を受け取ります。std::istringstream
オブジェクトiss
を作成し、入力文字列s
を渡します。std::string
型のitem
と、std::vector<std::string>
型のelems
を宣言します。std::getline
を使用して、iss
からデリミタdelim
までの一部分をitem
に読み込みます。- 読み込んだ
item
をelems
ベクトルに追加します。 - 最終的に
elems
ベクトルを返します。
main
関数:- 分割する文字列
str
とデリミタdelim
を定義します。 split
関数を呼び出して分割結果をresult
ベクトルに格納します。result
ベクトルの内容を出力します。
- 分割する文字列
解説
std::istringstream
は文字列をストリームとして扱うためのクラスです。std::getline
はストリームから指定されたデリミタまでの一行を読み込みます。std::vector
は動的配列で、分割された文字列を格納するために使用されます。
注意点
- このコードでは空のトークンをスキップしません。
- より複雑な分割ロジックが必要な場合は、正規表現ライブラリなどを使用することもできます。
拡張
- デリミタとして文字列を使用できるように拡張する。
- 空のトークンの処理を追加する。
- 大文字小文字を無視するオプションを追加する。
C++ での文字列分割 (パース) のコード解説
コード例 1: std::stringstream
と std::getline
を使った分割
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
std::vector<std::string> split(const std::string& s, char delim ) {
std::istringstream iss(s);
std::string item;
std::vector<std::string> elems;
while (std::getline(iss, item, delim )) {
elems.push_back(item);
}
return elems;
}
int main() {
std::string str = "apple,banana,orange";
char delim = ',';
std::vector<std::string> result = split(str, delim);
for (const std::string& word : result) {
std::cout << word << std::endl;
}
return 0;
}
コード解説
このコードは、入力文字列 str
をデリミタ delim
で分割し、結果を std::vector
に格納する関数 split
を定義しています。
-
ヘッダファイルのインクルード:
iostream
: 入出力ストリームのためのヘッダファイルstring
: 文字列操作のためのヘッダファイルvector
: 動的配列のためのヘッダファイル
-
split
関数の定義:const std::string& s
: 入力文字列の定数参照char delim
: デリミタ文字std::istringstream iss(s)
: 入力文字列をストリームに変換std::string item
: 一時的な文字列バッファstd::vector<std::string> elems
: 分割された文字列を格納するベクトルwhile (std::getline(iss, item, delim))
: デリミタまでの一行を読み込み、item
に格納elems.push_back(item)
: 読み込んだ文字列をelems
ベクトルに追加return elems
: 分割された文字列のベクトルを返す
boost::split
(Boostライブラリを使用する場合)- 正規表現による分割 (より複雑なパターンマッチングが必要な場合)
C++ での文字列分割の代替方法
前回までの復習
前回は、std::stringstream
と std::getline
を使った文字列分割の方法を解説しました。この方法は、標準ライブラリのみを使用し、比較的シンプルで読みやすいコードを書くことができます。
std::find と std::string::substr を使った方法
この方法は、文字列内のデリミタの位置を std::find
で検索し、その位置から次のデリミタまでの部分文字列を std::string::substr
で抽出します。
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> split(const std::string& s, char delim) {
std::vector<std::string> elems;
size _t start = 0;
size_t end = s.find(delim);
while (end != std::string::npos) {
elems.push_back(s.substr(start, end - start));
start = en d + 1;
end = s.find(delim, start);
}
if (start != s.length()) {
elems.push_back(s.substr(start));
}
return elems;
}
std::string::find_first_of と std::string::find_first_not_of を使った方法
この方法は、デリミタの最初の位置と次の非デリミタ文字の位置を検索し、その間の部分文字列を抽出します。
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> split(const std::string& s, char delim) {
std::vector<std::string> elems;
size_t pos = 0 ;
while (pos < s.length()) {
size_t next_delim = s.find_first_of(delim, pos);
elems.push_back(s.substr(pos, next_delim - pos));
pos = s.find_first_not_of(delim, next_delim);
}
return elems;
}
boost::split (Boostライブラリ)
Boostライブラリには、文字列分割のための boost::split
関数が提供されています。この関数は、より柔軟な分割オプションを提供します。
#include <iostream>
#include <string>
#include <vector>
#include <boost/algorithm/string.hpp>
std::vector<std::string> split(const std::string& s, char delim) {
std::vector<std::string> elems ;
boost::split(elems, s, boost::is_any_of(delim));
return elems;
}
正規表現
複雑な分割パターンが必要な場合は、正規表現を使用することができます。C++では、std::regex
クラスやサードパーティの正規表現ライブラリを利用できます。
性能と選択
これらの方法の性能は、文字列の長さ、デリミタの頻度、使用するコンパイラなどによって異なります。一般的には、std::stringstream
と std::getline
の組み合わせがバランスが取れており、多くの場合に適しています。
適切な方法を選択する際には、以下の点を考慮してください:
- コードの可読性: シンプルでわかりやすいコードが優先される場合、
std::stringstream
とstd::getline
が良い選択肢です。 - 性能: 高い性能が必要な場合は、ベンチマークを行い、最適な方法を選択してください。
- 機能性: 複雑な分割パターンが必要な場合は、正規表現を使用する必要があります。
注意:
- 上記のコード例は基本的な分割機能のみを提供しています。実際のアプリケーションでは、エラー処理や追加機能が必要になる場合があります。
- Boostライブラリを使用する場合は、適切にインストールする必要があります。
c++ parsing split