std::istringstream
空白で区切られた単語を読むのは簡単です。しかし、次の行を解析するには、文字/
を空白のように扱う必要があります。
f 104/387/104 495/574/495 497/573/497
スラッシュまたは空白で区切られた値を読み取るにはどうすればよいですか?
std::istringstream
空白で区切られた単語を読むのは簡単です。しかし、次の行を解析するには、文字/
を空白のように扱う必要があります。
f 104/387/104 495/574/495 497/573/497
スラッシュまたは空白で区切られた値を読み取るにはどうすればよいですか?
/
1 つの方法は、空白として分類される ctype ファセットを定義することです。
class my_ctype : public std::ctype<char> {
public:
mask const *get_table() {
static std::vector<std::ctype<char>::mask>
table(classic_table(), classic_table()+table_size);
table['/'] = (mask)space;
return &table[0];
}
my_ctype(size_t refs=0) : std::ctype<char>(get_table(), false, refs) { }
};
そこから、その ctype ファセットを使用してストリームにロケールを吹き込み、単語を読み取ります。
int main() {
std::string input("f 104/387/104 495/574/495 497/573/497");
std::istringstream s(input);
s.imbue(std::locale(std::locale(), new my_ctype));
std::copy(std::istream_iterator<std::string>(s),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(std::cout, "\n"));
}
ブーストが利用可能な場合boost::split()
、可能な解決策になります。usingstd::string
を入力してstd::getline()
から、行を分割します。
#include <iostream>
#include <vector>
#include <string>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
int main()
{
std::vector<std::string> tokens;
std::string line("f 104/387/104 495/574/495 497/573/497");
boost::split(tokens, line, boost::is_any_of("/ "));
for (auto& token: tokens) std::cout << token << "\n";
return 0;
}
出力:
へ 104 387 104 495 574 495 497 573 497
スラッシュまたは空白で分割するタイミングがわかっている場合は、使用できますstd::getline
std::istringstream is("f 104/387/104 495/574/495 497/573/497");
std::string f, i, j, k;
std::getline(is, f, ' ');
std::getline(is, i, '/');
std::getline(is, j, '/');
std::getline(is, k, ' ');
または、フォーマットされた入力を使用して、スラッシュを手動で破棄することもできます
std::string f;
int i, j, k;
char slash;
is >> f >> i >> slash >> j >> slash >> k;
これが最善の方法ではないことは確かですが、私はプログラミングの原則と C++ 2nd Ed を使用した実践という本の演習に取り組んでいました。Bjarne Stroustrupと私は、あなたに役立つかもしれない解決策を思いつきました。私は他の人がどのようにそれを行っているかを調べました(これが私がこのスレッドを見つけた方法です)が、実際には何も見つかりませんでした.
まず、本からの演習は次のとおりです。
引数 s から空白で区切られた部分文字列のベクトルを返す関数 vector<string> split(const string& s, const string& w) を記述します。空白は「通常の空白」に w の文字を加えたものとして定義されます。
これが私が思いついた解決策です。これはうまくいくようです。わかりやすいようにコメントしてみました。私は C++ にかなり慣れていないので (この本を読んでいるのもそのためです)、私を責めすぎないでください。:)
// split a string into its whitespace-separated substrings and store
// each string in a vector<string>. Whitespace can be defined in argument
// w as a string (e.g. ".;,?-'")
vector<string> split(const string& s, const string& w)
{
string temp{ s };
// go through each char in temp (or s)
for (char& ch : temp) {
// check if any characters in temp (s) are whitespace defined in w
for (char white : w) {
if (ch == white)
ch = ' '; // if so, replace them with a space char ('')
}
}
vector<string> substrings;
stringstream ss{ temp };
for (string buffer; ss >> buffer;) {
substrings.push_back(buffer);
}
return substrings;
}
次に、次のようにして使用できます。
cout << "Enter a string and substrings will be printed on new lines:\n";
string str;
getline(cin, str);
vector<string> substrings = split(str, ".;,?-'");
cout << "\nSubstrings:\n";
for (string s : substrings)
cout << s << '\n';
文字列を分割したくないことは承知していますが、これは他の文字を空白として扱う方法の例にすぎません。基本的に、これらの文字を「 」に置き換えるだけなので、文字通り空白になります。それをストリームで使用すると、かなりうまく機能します。for ループは、ケースに関連するコードである可能性があります。