ファイルの各行を各単語ではなく文字列として返す istream_iterator スタイルの反復子を取得したいと考えています。これは可能ですか?
8 に答える
編集:この同じトリックは、前のスレッドで他の誰かによって既に投稿されています。
std::istream_iterator
あなたが望むことをするのは簡単です:
namespace detail
{
class Line : std::string
{
friend std::istream & operator>>(std::istream & is, Line & line)
{
return std::getline(is, line);
}
};
}
template<class OutIt>
void read_lines(std::istream& is, OutIt dest)
{
typedef std::istream_iterator<detail::Line> InIt;
std::copy(InIt(is), InIt(), dest);
}
int main()
{
std::vector<std::string> v;
read_lines(std::cin, std::back_inserter(v));
return 0;
}
標準ライブラリはこれを行うためのイテレータを提供していませんが (独自にそのようなものを実装することはできます)、単純にgetline関数(istream メソッドではなく) を使用して、入力ストリームから C++ 文字列への行全体を読み取ることができます。 .
例:
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
ifstream is("test.txt");
string str;
while(getline(is, str))
{
cout<<str<<endl;
}
return 0;
}
これが解決策です。この例では、各行の終わりに @@ を付けて入力ファイルを出力します。
#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
using namespace std;
class line : public string {};
std::istream &operator>>(std::istream &is, line &l)
{
std::getline(is, l);
return is;
}
int main()
{
std::ifstream inputFile("input.txt");
istream_iterator<line> begin(inputFile);
istream_iterator<line> end;
for(istream_iterator<line> it = begin; it != end; ++it)
{
cout << *it << "@@\n";
}
getchar();
}
編集:マヌエルはより速くなりました。
独自のイテレータを作成できます。それほど難しくありません。イテレータは、(簡単に言えば) インクリメント演算子と * 演算子が定義されている単なるクラスです。
http://www.drdobbs.com/cpp/184401417を見て、独自のイテレータを書き始めてください。
istream_iterator の代わりに istreambuf_iterator を使用できます。istream_iterator のような制御文字は無視されません。
コード.cpp:
#include <iterator>
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream file("input.txt");
istreambuf_iterator<char> i_file(file);
istreambuf_iterator<char> eof;
std::string buffer;
while(i_file != eof)
{
buffer += *i_file;
if(*i_file == '\n')
{
std::cout << buffer;
buffer.clear();
}
++i_file;
}
return 0;
}
入力.txt:
ahhhh test *<-- There is a line feed here*
bhhhh second test *<-- There is a line feed here*
出力:
ahhhh test
bhhhh second test
範囲ベースの for ループを使用することも可能です:
// Read from file.
std::ifstream f("test.txt");
for (auto& line : lines(f))
std::cout << "=> " << line << std::endl;
// Read from string.
std::stringstream s("line1\nline2\nline3\n\n\nline4\n\n\n");
for (auto& line : lines(s))
std::cout << "=> " << line << std::endl;
はlines
次のように定義されます。
#include <string>
#include <iterator>
#include <istream>
struct line_iterator {
using iterator_category = std::input_iterator_tag;
using value_type = std::string;
using difference_type = std::ptrdiff_t;
using reference = const value_type&;
using pointer = const value_type*;
line_iterator(): input_(nullptr) {}
line_iterator(std::istream& input): input_(&input) { ++*this; }
reference operator*() const { return s_; }
pointer operator->() const { return &**this; }
line_iterator& operator++() {
if (!std::getline(*input_, s_)) input_ = nullptr;
return *this;
}
line_iterator operator++(int) {
auto copy(*this);
++*this;
return copy;
}
friend bool operator==(const line_iterator& x, const line_iterator& y) {
return x.input_ == y.input_;
}
friend bool operator!=(const line_iterator& x, const line_iterator& y) {
return !(x == y);
}
private:
std::istream* input_;
std::string s_;
};
struct lines {
lines(std::istream& input): input_(input) {}
line_iterator begin() const { return line_iterator(input_); }
line_iterator end() const { return line_iterator(); }
private:
std::istream& input_;
};