C++ で文字列を単語ごとに処理するコード解説
C++ で文字列を単語ごとに処理する
C++ で文字列を単語ごとに処理するには、いくつかの方法があります。ここでは、最も一般的な方法である istringstream
を使った方法と、手動で分割する方法について説明します。
istringstream
を使った方法
#include <iostream>
#include <string>
#include <sstream>
int main() {
std::string str = "これは テスト の 文字列 です";
std::istringstream iss(str);
std::string word;
while (iss >> word) {
std::cout << word << std::endl;
}
return 0;
}
- 解説:
#include <iostream>
: 入出力ストリームのためのヘッダファイル#include <string>
: 文字列操作のためのヘッダファイルstd::string str = "これは テスト の 文字列 です";
: 文字列を定義std::istringstream iss(str);
: 文字列をistringstream
オブジェクトに変換std::string word;
: 単語を格納する変数while (iss >> word)
:istringstream
から単語を読み込むループstd::cout << word << std::endl;
: 読み込んだ単語を出力
手動で分割する方法
#include <iostream>
#include <string>
int main() {
std::string str = "これは テスト の 文字列 です";
int start = 0, end = 0;
while (end != std::string::npos) {
end = str.find(' ', start);
std::string word = str.substr(start, end - start);
std::cout << word << std::endl;
start = end + 1;
}
return 0;
}
- 解説:
int start = 0, end = 0;
: インデックス用の変数while (end != std::string::npos)
: 文字列の終わりまでループend = str.find(' ', start)
: 次の空白の位置を探すstd::string word = str.substr(start, end - start)
: 単語を切り出すstart = end + 1
: 次の単語の開始位置を設定
boost::split
: Boost ライブラリのsplit
関数を使用std::regex
: 正規表現を使って分割
注意:
- 上記のコードは基本的な例であり、実際のアプリケーションではエラー処理やパフォーマンスの考慮が必要になる場合があります。
istringstream
の方が一般的にシンプルで使いやすいですが、パフォーマンスが重要な場合は手動分割や他の方法を検討する必要があります。
#include <iostream>
#include <string>
#include <sstream>
int main() {
std::string str = "これは テスト の 文字列 です";
std::istringstream iss(str);
std::string word;
while (iss >> word) {
std::cout << word << std::endl;
}
return 0;
}
- コードの説明:
std::string str = "これは テスト の 文字列 です";
: 文字列 "これは テスト の 文字列 です" をstr
という名前の変数に代入します。std::istringstream iss(str);
: 文字列str
をistringstream
オブジェクトiss
に変換します。これにより、文字列をストリームとして扱うことができるようになります。std::string word;
: 単語を格納するための空の文字列word
を宣言します。while (iss >> word)
:iss
から次の単語をword
に読み込むループです。読み込みが成功する限りループが続きます。return 0;
: プログラムが正常終了したことを示すために 0 を返します。
コード例 2: 手動で分割する方法
#include <iostream>
#include <string>
int main() {
std::string str = "これは テスト の 文字列 です";
int start = 0, end = 0;
while (end != std::string::npos) {
end = str.find(' ', start);
std::string word = str.substr(start, end - start);
std::cout << word << std::endl;
start = end + 1;
}
return 0;
}
- コードの説明:
int start = 0, end = 0;
: 文字列内のインデックスを管理するための変数start
とend
を宣言し、初期値を 0 に設定します。while (end != std::string::npos)
:end
が文字列の末尾を示す特別な値std::string::npos
でない限りループを続けます。end = str.find(' ', start)
: 文字列str
内で、インデックスstart
から始まる次の空白文字の位置を探し、その位置をend
に代入します。std::string word = str.substr(start, end - start)
:start
からend - start
の長さの部分文字列をword
に代入します。つまり、現在の単語を切り出します。start = end + 1
: 次の単語の開始位置としてend + 1
をstart
に代入します。
C++ での文字列分割の代替方法
これまで istringstream
と手動分割の方法を紹介しましたが、他にもいくつかの方法があります。
Boost ライブラリを利用した方法
Boost ライブラリは、C++標準ライブラリを拡張する高品質なライブラリ集です。その中の boost::split
関数を使うことで、簡単に文字列を分割できます。
#include <iostream>
#include <string>
#include <vector>
#include <boost/algorithm/string.hpp>
int main() {
std::string str = "これは テスト の 文字列 です";
std::vector<std::string> words;
boost::split(words, str, boost::is_any_of(" "));
for (const auto& word : words) {
std::cout << word << std::endl;
}
return 0;
}
- 解説:
boost::split
関数は、第一引数に分割結果を格納するコンテナ、第二引数に分割対象の文字列、第三引数に分割基準を渡します。boost::is_any_of(" ")
は、空白文字で分割することを指定します。
正規表現を利用した方法
C++11 以降、正規表現が標準ライブラリに含まれています。 std::regex
と std::sregex_token_iterator
を使って、複雑なパターンでの分割が可能です。
#include <iostream>
#include <string>
#include <vector>
#include <regex>
int main() {
std::string str = "これは テスト の 文字列 です";
std::regex re("\\s+"); // 空白文字1個以上の正規表現
std::sregex_token_iterator iter(str.begin(), str.end(), re, -1);
std::sregex_token_iterator end;
for (; iter != end; ++iter) {
std::cout << *iter << std::endl;
}
return 0;
}
- 解説:
std::regex
で正規表現パターンを定義します。std::sregex_token_iterator
は、正規表現に基づいて文字列をトークン化するイテレータです。
- getline 関数:
std::getline
関数は、通常は入力ストリームから1行読み込むために使用されますが、istringstream
と組み合わせることで文字列を分割することもできます。 - 手動ループ:
find
関数を使って空白文字の位置を逐次探す方法の改良版として、ループ内で文字列を処理する方法も考えられます。
性能と使いやすさ
- 性能: 一般的に、
istringstream
やboost::split
が高速です。手動ループや正規表現は、複雑なパターンや大規模な文字列の場合に性能が低下する可能性があります。 - 使いやすさ:
boost::split
やstd::regex
は、複雑な分割パターンに対応できるため、柔軟性が高いです。しかし、それらのライブラリを使用するため、コードの依存性が増えます。
c++ string split