web-dev-qa-db-ja.com

行ごとにファイルを反復処理できるC ++イテレータはありますか?

ファイルの各行を各Wordではなく文字列として返すistream_iteratorスタイルのイテレータを取得したいと思います。これは可能ですか?

46
thehouse

EDIT:この同じトリックはすでに他の誰かによって投稿されていました 前のスレッドで

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;
}
27
Manuel

標準ライブラリはこれを行うためのイテレータを提供していません(独自にそのようなものを実装できます)が、単に getlinefunction (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;
}
22
Matteo Italia

これが解決策です。例では、各行の最後に@@を付けて入力ファイルを出力します。

#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();
}

編集:マヌエルはより高速になりました。

5
Rexxar

独自のイテレータを作成できます。そんなに難しくありません。イテレータは、単純にインクリメントと*演算子が定義されているクラスです。

http://www.drdobbs.com/cpp/184401417 を見て、独自のイテレーターの作成を始めてください。

4
Patrick

Istream_iteratorの代わりにistreambuf_iteratorを使用できます。 istream_iteratorのような制御文字を無視しません。

code.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;
}

input.txt:

ahhhh test *<-- There is a line feed here*
bhhhh second test *<-- There is a line feed here*

出力:

ahhhh test
bhhhh second test
2
coelhudo

上記の関連スレッド iterate-over-cin-line-by-line で、Jerry Coffinは「ほとんどの人がほとんど知らない標準ライブラリの一部を使用する別の可能性」を説明しました。以下は、そのメソッド(私が探していたもの)を適用して、現在のスレッドで要求されているファイルごとの反復処理の問題を解決します。

最初に、関連するスレッドのJerryの回答から直接コピーされたスニペット:

struct line_reader: std::ctype<char> {
line_reader(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
    static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask());
    rc['\n'] = std::ctype_base::space;
    return &rc[0];
}}; 

そして、Jerryによって記述されたカスタムロケールをifstreamに吹き込み、infstreamからofstreamにコピーします。

ifstream is {"fox.txt"};
is.imbue(locale(locale(), new line_reader()));
istream_iterator<string> ii {is};
istream_iterator<string> eos {};

ofstream os {"out.txt"};
ostream_iterator<string> oi {os,"\n"};

vector<string> lines {ii,eos};
copy(lines.begin(), lines.end(), oi);

出力ファイル( "out.txt")は、入力ファイル( "fox.txt")とまったく同じです。

0
winvicta