2010-02-18 4 views
38

Ich möchte einen istream_iterator-Iterator erhalten, der jede Zeile der Datei als Zeichenfolge statt jedes Wort zurückgibt. Ist das möglich?Gibt es einen C++ Iterator, der Zeile für Zeile über eine Datei iterieren kann?

+1

Ich denke, Sie könnten immer Ihre eigenen mit der Funktion getline() schreiben, wie Matteo Italia sagte. –

+1

Duplizieren: http://stackoverflow.com/questions/1567082/how-do-i-iterate-over-cin-line-by-line-in-c/1567703 –

+3

@Jerry: Dieser Thread enthält die Antwort. Aber die Frage ist völlig anders. – UncleBens

Antwort

25

EDIT: Der gleiche Trick bereits von jemandem anderen in a previous thread gebucht wurde.

Es ist leicht std::istream_iterator zu tun haben, was Sie wollen:

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; 
} 
+0

Vererbt die Übernahme von std :: string hier nicht Regel 35 des C++ - Codierungsstandards: "Vermeiden Sie das Erben von Klassen, die nicht als Basisklassen konzipiert wurden"? – thehouse

+4

@thehouse - Welchen Kodierungsstandard meinen Sie? Ich denke nicht, dass es etwas Falsches daran gibt, eine beliebige Klasse als Basis zu verwenden, vorausgesetzt, dass sie nicht in einem polymorphen Kontext verwendet wird. Zum Beispiel wäre das Vererbungsschema in meiner Antwort gefährlich, wenn ich Dinge wie "string * ptr = new Line; delete ptr; 'aber das ist hier nicht der Fall – Manuel

+0

@Manuel: Herb Sutter und Andrei Alexandrescu in ihrem Buch C++ Coding Standards erklären, dass" die Verwendung einer eigenständigen Klasse als Basis ein schwerwiegender Designfehler ist und vermieden werden sollte ". Sie erwähnen String dann explizit als eine schlechte Klasse, von der er erbt. Ihr Argument dreht sich um die Tatsache, dass Sie eine Reihe von Dingen tun müssen, um eine Basisklasse zum sicheren Arbeiten zu bekommen, und eine widersprüchliche Menge von Dingen, um sichere Klassen sicher zu machen. – thehouse

15

Die Standardbibliothek stellt keine Iteratoren zur Verfügung (obwohl Sie so etwas selbst implementieren können), aber Sie können einfach die getline function (nicht die iStream-Methode) verwenden, um eine ganze Zeile aus einem Eingabestream zu lesen eine C++ - Zeichenfolge.

Beispiel:

#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; 
} 
+0

Handelt es sich um den Unterschied in eol Zeichen für die verschiedenen Plattformen (Windows/Unix/Mac)? –

+1

Dieser Unterschied wird bereits im stream-Objekt behandelt: Wenn Sie eine Datei im Textmodus öffnen (der Standard, wenn Sie das Flag 'ios :: binary' nicht angeben), konvertiert der Stream das plattformspezifische EOL automatisch in '' n'. –

+0

wir verwenden einen COM-istream, der die EOLs nicht gleich behandelt hat. Das Parsen einer Dos-Datei funktionierte, aber das Parsen einer UNIX-Datei (keine LF-Datei) führte dazu, dass sie so gehandhabt wurde, als wäre sie eine große Zeile. –

4

Sie Ihren eigenen Iterator schreiben konnte. Es ist nicht so schwer. Ein Iterator ist nur eine Klasse, auf der (einfach gesagt) die Inkrement- und * Operatoren definiert sind.

Schauen Sie sich http://www.drdobbs.com/cpp/184401417 an, um mit dem Schreiben eigener Iteratoren zu beginnen.

+3

@thehouse: Sie könnten auch 'boost :: iterator_facade' ausprobieren, das das vollständige STL-Iterator-Konzept in Bezug auf einige Kernfunktionen implementiert. –

1

Sie können istreambuf_iterator anstelle von isteam_iterator verwenden. Kontrollzeichen wie istream_iterator werden nicht ignoriert.

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* 

Ausgang:

ahhhh test 
bhhhh second test 
5

Hier ist eine Lösung. Das Beispiel druckt die Eingabedatei mit @@ am Ende jeder Zeile.

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

Edit: Manuel war schneller.

+0

@Rexxar - Mein Fehler, ich habe es gelöscht und dann als Community-Wiki wiederhergestellt. Das tut mir leid. – Manuel