Datei einlesen, Inhalt vom Header trennen und in Array Speichern
-
Hallo zusammen ...
Mein Problem klingt wahrscheinlich total simpel, aber ich tu mich irgendwie sehr schwer daran.
Ich habe eine Dateien, welche in einem festen Format vorliegen, welches ich nicht beeinflussen kann. Ich muss also sozusagen damit leben.
Die Dateien haben ungefähr folgenden Aufbau:Header Hier stehen paar Sachen drin... Die Zeilen sind zwar unterschiedlich lang... Aber die Anzahl der Zeilen im Header ist gleich... Danach kommen die "nutzdaten" \t \t 1.5 \t \t \t 1.2 0.0 1.3 \t \t \t 1.0 \t \tNach dem Header kommt also eine Art Array von double-Zahlen. Diese sind in Zeilen und Spalten angeordnet. Die Spalten sind jeweils durch einen Tabulator voneinander getrennt.
Das Problem ist nun, überall wo der Wert 0.0 stehen würde, steht gar nichts hin. Obiges double-Array steht also eigentlich für:0.0 0.0 1.5 0.0 0.0 0.0 1.2 0.0 1.3 0.0 0.0 0.0 1.0 0.0 0.0Mein erster Gedanke war, dass gleich als eine Art Struktur einlesen zu lassen. Aber das geht ja so richtig nur, wenn der Inhalt binär vorliegt.
Dann wollte ich das "einfach" überifstream File("Datei.txt"); string s; ... File >> s; ... File.close();einlesen (ist jetzt nur schematisch zu verstehn).
So habe ich aber das Problem, dass die Felder in denen nichts als nen Tab steht "übersprungen" werden.
Wenn ich also das Array nacheinander einlese, bekomme ich nur 1.5, 1.2, 1.3 und 1.0. Ich verliere also sämtliche Nullen und auch die Positionen, wo sie sind.Hat vielleicht jemand nen guten Tipp für mich?

-
Bei der Funktion getline kannst du Trennzeichen angeben...
-
SeppJ schrieb:
Bei der Funktion getline kannst du Trennzeichen angeben...
.. dieser automatische Reflex auf das Schlüsselwort 'Datei einlesen' oder 'einlesen' mit 'getline' zu reagieren, empfinde ich langsam als ziemlich nervig.
Nix für ungut SeppJ, ansonsten schätze ich Deine Beiträge durchaus.

Das Überlesen von Zeilen macht man mit ignore - ein Code Schnipsel dazu:
#include <iostream> #include <fstream> #include <limits> // numeric_limits namespace { const std::streamsize ALL = std::numeric_limits< std::streamsize >::max(); } int main() { using namespace std; ifstream File("Datei.txt"); const int anzahlZeilenImHeader = 5; for( int i=0; i < anzahlZeilenImHeader; ++i ) File.ignore( ALL, '\n' ); // Zeile bis LF überlesen // usw.Das mit dem Lesen der leeren(!) Tabulatoren ist schwieriger, da der Tabulator zu den White Space Zeichen gehört und der std::istream von Haus aus alle White Space gleich behandelt. Überlege ich mir noch ...
Gruß
Werner
-
Hallo Mandel,
ich habe zwei Helferlein gebastelt. Zum einen 'tab', was ein Tabulator-Zeichen einliest und die Abfrage 'is_number', welche true liefert, wenn ein Zeichen folgt, dass eine Zahl einleiten könnte. Damit kann man dann relativ einfach die von Dir beschriebene Datei einlesen (s. main).
Damit das funktioniert, muss vor jeder potentiellen Zahl (auch der in der ersten Spalte) ein TAB stehen - unabhängig davon, ob danach eine Zahl kommt oder nicht. Weiter gehe ich davon aus, dass die Anzahl der Spalten vor dem Einlesen bekannt ist (im Programm unten == 5).
Hier der gesamte Code
#include <iostream> #include <fstream> #include <limits> // numeric_limits // -- liest das nächste Tabulator-Zeichen ein // falls keines gefunden wurde, oder Text folgt, so wird der Stream auf FAIL gesetzt template< typename E, typename Traits > std::basic_istream< E, Traits >& tab( std::basic_istream< E, Traits >& in ) { std::basic_istream< E, Traits >::sentry ok( in, true ); // true := noskip white space if( ok ) { const std::ctype< E >& ctype_ = std::use_facet< std::ctype< E > >( in.getloc() ); for( std::basic_istream< E, Traits >::int_type m = in.rdbuf()->sgetc(); ; m = in.rdbuf()->snextc() ) { if( Traits::eq_int_type( m, Traits::eof() ) ) { in.setstate( std::ios_base::eofbit | std::ios_base::failbit ); break; // EOF ist hier auch Fehler, da ein Tab gelesen werden soll } const E c = Traits::to_char_type( m ); if( c == in.widen( '\t' ) ) { in.rdbuf()->sbumpc(); // Tabulator konsumieren break; // ok, Tab gelesen } if( !ctype_.is( std::ctype_base::space, c ) ) { in.setstate( std::ios_base::failbit ); break; // .. es folgt ein Text -> das ist wäre hier ein Fehler - oder?! } } } return in; } // -- liefert true, wenn im unmittelbar folgenden Zeichen des Streams 'in' // ein Zeichen folgt, welches zu einem numerischen Ausdruck gehören könnte. // e := { Digit, Vorzeichen, Dezimalpunkt } // Es wird kein Zeichen konsumiert (d.h. eingelesen). // Ist das aktuelle Zeichen das letzte im Stream, so wird EOF gesetzt. // Ist EOF bereits gesetzt, so geht der Stream auf FAIL (s. istream::sentry). template< typename E, typename Traits > bool is_number( std::basic_istream< E, Traits >& in ) { std::basic_istream< E, Traits >::sentry ok( in, true ); // true := noskip white space if( ok ) { const std::basic_istream< E, Traits >::int_type m = in.rdbuf()->sgetc(); if( Traits::eq_int_type( m, Traits::eof() ) ) { in.setstate( std::ios_base::eofbit ); return false; } const E c = Traits::to_char_type( m ); return std::use_facet< std::ctype< E > >( in.getloc() ).is( std::ctype_base::digit, c ) || c == in.widen('-') || c == in.widen('+') || c == std::use_facet< std::numpunct< E > >( in.getloc() ).decimal_point(); } return false; } namespace { const std::streamsize ALL = std::numeric_limits< std::streamsize >::max(); } int main() { using namespace std; ifstream File("Datei.txt"); if( !File.is_open() ) { cerr << "Fehler beim Oeffnen der Datei" << endl; return -1; } // -- Header überlesen const int anzahlZeilenImHeader = 6; for( int i=0; i < anzahlZeilenImHeader; ++i ) File.ignore( ALL, '\n' ); // Zeile bis LF überlesen // -- Tabelle einlesen; bis Fehler oder Ende for( int zeile = 0; File; ++zeile ) { for( int spalte = 0; spalte < 5; ++spalte ) // mal angenommen es sind 5 Spalten! { double num = 0.0; // Defaultwert, falls keine Zahl in der Datei steht if( File >> tab && (!is_number( File ) || File >> num) ) { cout << '\t' << num; // hier ist 'num' in [zeile,spalte] gültig } else break; // Lesefehler bzw. EOF } cout << endl; } if( !File.eof() ) cerr << "beim Lesen ist ein Fehler aufgetreten" << endl; return 0; }Gruß
Werner