std::ifstream_iterator<std::basic_string<T> > - Stoppzeichen definieren
-
Hi,
ich möchte eine Textdatei Zeilenweise mittels 'ifstream_iterator' auslesen, also habe ich mir eine Methode geschrieben, die in etwa so ausschaut:template<typename char_type> const std::basic_string<char_type> basic_textfile<char_type>::read(unsigned int line) { // 'stream_' ist ein gültiges 'std::basic_fstream<char_type'-Objekt std::istream_iterator<std::basic_string<char_type> > iter(stream_), eos; for(unsigned int i=0; (++i<line) && (iter!=eos); ++iter); return *iter; }Kompiliert und arbeitet einwandfrei, bis auf den Umstand, dass scheinbar die Zeilen nicht immer bis zum Ende gelesen werden, sondern schon beim Auftreten von Leerzeichen abgebrochen wird.
Beispiel für eine Textdatei:
muh
miau
wau wau
grunzVersuch' ich nun mittels o.g. Funktion die 3. Zeile zu lesen, bekomme ich natürlich nicht "wau wau" geliefert wie gewollt, sondern nur "wau". Meine Frage: Wie erreiche ich, dass dieses Leerzeichen im Strom ignoriert, bzw. vom Iterator übergangen wird? Geht das irgendwie auch ohne eine neue Iterator- oder Stringklasse abzuleiten?
Google hilft leider kaum, da das Problem ja doch schon sehr speziell ist. Achja, mir ist natürlich bewusst, dass man diese Problemstellung auch anders bewältigen könnte, beispielsweise mittels 'getline' oder 'read', hab' ich auch schon 1000x gemacht, aber ich finde diese Variante am schönsten und bin auf jeden Fall an einer Lösung interessiert.
-
Geht das irgendwie auch ohne eine neue Iterator- oder Stringklasse abzuleiten?
Ich fürchte, das geht nicht - der istream_iterator verwendet op>> zum Einlesen und der stoppt beim ersten Whitespace. Du könntest höchstens ein neues Locale definieren, das nur das \n als Whitespace anerkennt (braucht einige Anpassungen in der Facette "ctype") - oder du definierst dir einen eigenen line_iterator auf Basis von getline().
(letzteres ist wohl einfacher umzusetzen)
-
Hm, das ist schade, jedenfalls danke für deine Hilfe, ich werd's wohl so machen denk ich.
-
#include <cstdlib> #include <iostream> #include <fstream> #include <iterator> #include <string> using namespace std; int main() { ifstream fs("datei"); fs.unsetf(ios_base::skipws); // !!! istream_iterator<char> ii(fs), eos; while (ii != eos) cout << *ii++; return EXIT_SUCCESS; }out schrieb:
muh
miau
wau wau
grunz
-
Sowas hatte ich gesucht.
Ich war so fixiert darauf, die Lösung beim Iterator zu suchen, dass ich an die Format-Flags gar nicht mehr gedacht hatte. Leider funktioniert das so auch noch nicht ganz, da durch das Deaktiveren des 'skipws'-Flags leider auch die "line feed"-Zeichen etc. ignoriert werden und ein zeilenweises Lesen in 'std::basic_string<T>' nicht mehr möglich ist, oder ich stelle mich nur zu dumm an.Ein Gedanke den ich noch hatte: Eventuell einen Algorithmus definieren (eventuell 'copy_if') und dann Zeichen für Zeichen in den String kopieren, bis auf ein "line feed"-Zeichen gestoßen wird. Allerdings müsste ich dazu wiederum einen Algorithmus schreiben (mir ist zumindest keiner im Standard bekannt, der das Gewünschte leistet) und einen Functor für die Bedingung. Eine Konstruktion mit 'copy' und 'find' würde vielleicht auch funktionieren.
Am Schönsten wäre es natürlich, wenn es so einfach funktionieren würde à la "whitespaces" ignorieren aber "feed line" mitnehmen.
-
GreveN schrieb:
Allerdings müsste ich dazu wiederum einen Algorithmus schreiben (mir ist zumindest keiner im Standard bekannt, der das Gewünschte leistet) und einen Functor für die Bedingung.
remove_copy_if mit invertiertem prädikat:
template<typename InputIterator, typename OutputIterator, typename Predicate> OutputIterator copy_if(InputIterator first, InputIterator last, OutputIterator result, Predicate pred) { return std::remove_copy_if( first, last, result, std::not2( pred ) ); }
-
camper schrieb:
remove_copy_if mit invertiertem prädikat
