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


Anmelden zum Antworten