Einlesen aus einer .txt Datei
-
Hallo,
ich habe eine .txt in der zuerst ein int Wert steht und darauffolgend eine Reihe von double Werten. Jede Zahl ist durch ein '\t' getrennt.2015 3848,3 322,2 99,232 12,453 2016 23,23 -394,9 2,321 2342,45 usw
Man beachte das bei den double Werten die Trennung zwischen vor-und nachkommastellen durch ein Komma geschieht und nicht durch ein Punkt.
Meine Frage ist nun, wie les ich das in jeweils int und double werte ein? Muss ich da wirklich sowas in der Richtung machen (im Falle der double werte):
string zahl; getline(Textdatei, zahl, '\t');
Und dann mittels replace irgendwie das Komma in einen Punkt umwandeln und dann
double zahl1 = stod(zahl);
den String in ein double umkonvertieren?
Oder gibt es da auch einen eleganten Weg (falls der oben genannte überhaupt richtig ist)?
Und mal angenommen die Vor-und Nachkommastellen der double Werte wären richtig durch Punkt getrennt, ich kann dann ja die Werte mit dem >> Operator einlesen
int a; double b; Textdatei>>a; Textdatei>>b;
(vereinfach dargestellt, mir gehts nur ums Prinzip)
Das funktioniert für die erste Zeile, aber ab der zweiten werden die Werte nicht mehr korrekt eingelesen. Wie mach ich das richtig, dass der für alle zeilen die werte richtig einliest?
Kann da wer helfen danke.
mfg
-
Du könntest z.B.
std::locale::global(std::locale("de_DE.UTF-8")); stringstream ss("4\t1,3\t2,5"); int i; double d1,d2; cout << (bool)(ss>>i>>d1>>d2) << "\n"; cout << "int=" << i << ", d1*d2=" << d1*d2 << "\n";
Aber zum Glück musste ich selbst noch nie mit locales rumhantieren
-
Schau dir dafür mal boost::tokenizer an, der ist dafür wie geschaffen und kommt auch mit typensicherer Konvertierung:
http://www.boost.org/doc/libs/1_62_0/libs/tokenizer/tokenizer.htm
-
Hallo vivess,
wob hat es schon geschrieben. Man kann dem Stream mit einem 'locale' mitteilen, dass man einen 'deutschen' Dezimaltrenner hat. Leider sind die Locale-Namen in C++ nicht standardisiert. Microsoft verwendet das Format <language>-<REGION>. Und <language> ist nach ISO 639-1 genormt - hier 'de' für deutsch.
Der gesamte Code sähe z.B. so aus:
#include <array> #include <fstream> #include <iostream> #include <vector> struct Datensatz // es bietet sich an, einen Datensatz in eine struct oder class zu fassen { int jahr_; std::array< double, 4 > werte_; }; std::istream& operator>>( std::istream& in, Datensatz& d ) // .. und dann schreibe man sich einen 'Inserter' { in >> d.jahr_; // ein int for( auto& datum: d.werte_ ) // und 4 double in >> datum; return in; } int main() { using namespace std; vector< Datensatz > alle_daten; // hier kommt alles, was gelesen wird, rein ifstream textdatei("input.txt"); if( !textdatei.is_open() ) { cerr << "Fehler beim Oeffnen der Datei" << endl; return 0; } textdatei.imbue( locale("de-DE") ); // für MS: locale Name ist <language>-<REGION> wobei <language> nach ISO 639-1 gemeint ist for( Datensatz d; textdatei >> d; ) // .. und ab hier ist es wirklich einfach { alle_daten.push_back( d ); } cout << alle_daten.size() << " Datensaetze gelesen" << endl; return 0; }
Scorcher24 schrieb:
Schau dir dafür mal boost::tokenizer an, der ist dafür wie geschaffen und kommt auch mit typensicherer Konvertierung:
std::istream ist ebenso typsicher, aber das wissen die wenigsten
Gruß Werner
-
Werner Salomon schrieb:
std::istream ist ebenso typsicher, aber das wissen die wenigsten
Gruß Werner
Hab ich ja nicht bestritten, aber fürs einlesen der Nummern ist der tokenizer 1A und auch bewährt. Weniger bugs, mehr action.
-
Scorcher24 schrieb:
Werner Salomon schrieb:
std::istream ist ebenso typsicher, aber das wissen die wenigsten
Gruß Werner
Hab ich ja nicht bestritten, aber fürs einlesen der Nummern ist der tokenizer 1A und auch bewährt. Weniger bugs, mehr action.
Ja - schön. Dann poste uns doch mal einen kleinen Dreizeiler, damit man sieht wie das geht. Ich hab's nämlich so auf Anhieb nicht hinbekommen ...
Gruß
Werner
-
std::getline(in_stream, line); const boost::char_delimiters_separator<char> separator(" "); boost::tokenizer<> tokenizer(line, separator); auto iterator = tokenizer.begin(); float sample = boost::lexical_cast<float>(*iterator );
-
Was macht der boost-Code genau? Ich würde erwarten, dass hier nur Leerzeichen als Trennzeichen in Frage kommen, aber es wird munter auch bei /, - und bei Tabs getrennt.
-
Scorcher24 schrieb:
std::getline(in_stream, line); const boost::char_delimiters_separator<char> separator(" "); boost::tokenizer<> tokenizer(line, separator); auto iterator = tokenizer.begin(); float sample = boost::lexical_cast<float>(*iterator );
Funktioniert nicht! Angewandt auf auf die Problemstellung von vivess sähe es doch so aus:
#include <boost/tokenizer.hpp> #include <boost/token_functions.hpp> #include <boost/lexical_cast.hpp> #include <iostream> #include <string> int main() { // std::getline( in_stream, line ); std::string line = "2015 3848,3 322,2 99,232 12,453"; // siehe vivees Beitrag const boost::char_delimiters_separator<char> separator(" "); boost::tokenizer<> tokenizer(line, separator); for( auto iterator = tokenizer.begin(); iterator != tokenizer.end(); ++iterator ) { std::cout << "aus '" << *iterator << "'"; float sample = boost::lexical_cast<float>(*iterator ); // ...und ich dachte, die Konvertierung wird von boost::tokenizer erledigt!? std::cout << " wird: " << sample << std::endl; } return 0; }
Liefert:
aus '2015' wird: 2015 aus '3848' wird: 3848 aus ',' <Exception>
atrium schrieb:
Was macht der boost-Code genau? Ich würde erwarten, dass hier nur Leerzeichen als Trennzeichen in Frage kommen, aber es wird munter auch bei /, - und bei Tabs getrennt.
Ja- genau so sieht das aus. Und was muss man tun, damit boost::tokenizer mit dem Komma als Dezimaltrenner klar kommt? Und was soll das lexical_cast? Ich zitiere:
Scorcher24 schrieb:
.. aber fürs einlesen der Nummern ist der tokenizer 1A und auch bewährt. Weniger bugs, mehr action.
.. 'mehr action' ist richtig. Ansonsten bin ich nicht überzeugt.
Gruß
Werner