string-variablen aus Textdatei lesen und in integer-Feld schreiben



  • Hallo Werner,

    viel verstehe ich leider nicht.

    hier erzeugst du eine Funktionsvorlage, aber warum?

    template< char C >
    std::istream& Char( std::istream& in )
    {
        char c;
        if( in >> c && c != C )
            in.setstate( std::ios_base::failbit );
        return in;
    }
    

    Ist struct eine Ansammlung von Werten verschiedener Datentypen, in dem Fall halt mal gleich? Wozu brauch ich das?

    struct Foo	
    {
    int m_var, m_uGrenze, m_oGrenze;
    };
    

    Was passiert hier? Liest das Programm das Objekt x ein? Was bedeutet das &?:

    std::istream& operator>>( std::istream& in, Foo& x ) 
    {
        return in >> x.m_var >> Char<';'> >> x.m_uGrenze >> Char<';'> >> x.m_oGrenze;
    }
    

    Den folgenden Abschnitt versteh ich leider auch nicht...Kannst du das noch etwas beschreiben?

    std::istream& read3DArray( std::istream& in, std::vector< Foo >& dreiD_ )
    {
        in.ignore( std::numeric_limits< std::streamsize >::max(), ':' );
        std::size_t anzahl;
        char dummy; // das Lesen des 'dummy' garantiert, das sich der Lesezeiger in der Kommenatrzeile befindet
        if( (in >> anzahl >> dummy)
                .ignore( std::numeric_limits< std::streamsize >::max(), '\n' ) ) // Kommentar überlesen
        {
            std::vector< Foo > dreiD;
            dreiD.reserve( anzahl );    // optional
            for( Foo x; anzahl && in >> x; --anzahl )
                dreiD.push_back( x );
            if( in )
                swap( dreiD, dreiD_ );  // ok; dann übernehmen
        }
        return in;
    }
    

    Danke für deine Mühe, ich hab leider bis jetzt nur mit statischen Feldern gearbeitet...

    Grüße

    Guddy



  • Wiedermal wunderschön Werner. Ist man bei dir ja auch inzwischen nicht anders gewöhnt, wenns vorallem um Streams geht 🙂

    Insbesondere die Idee mit dem Char<';'> gefällt mir außerordentlich gut 👍
    [Code in Lesezeichen save]



  • Wozu ist das "Char<';'>" gut? Danke.



  • Hallo,

    hab mir das ganze nochmal reingezogen und einiges verstanden, denk ich. Ich hab mal Kommentare in den Quelltext geschrieben. Vielleicht könnt ihr mir Feedback geben ob ich das richtig vestehe oder nicht.

    t

    emplate< char C >
    std::istream& Char( std::istream& in )
    {
        char c;
        if( in >> c && c != C )
            in.setstate( std::ios_base::failbit );
        return in;
    }
    
    struct Foo
    {
        int m_var, m_uGrenze, m_oGrenze;
    };
    std::istream& operator>>( std::istream& in, Foo& x ) //formatierter input (was bedeuten die Werte in den Klammern? in=Name des iputstream?? und Ausgabe in x??
    {
        return in >> x.m_var >> Char<';'> >> x.m_uGrenze >> Char<';'> >> x.m_oGrenze; //gibt Werte des inputstream in zurück aber ohne ";"? und zwar in die Variablen der Strucktur x?
    }
    
    std::istream& read3DArray( std::istream& in, std::vector< Foo >& dreiD_ ) //Definier von istream abgeleitete Funktion read3DArray mit inputstreamquelle  in und Ziel vector dreiD_ mit daten-bzw. structurtyp Foo 
    {
        in.ignore( std::numeric_limits< std::streamsize >::max(), ':' ); // ignore(streamlänge, Zeichen) ignoriert Strom bis zu dem Punkt, wenn Streamlänge erreicht oder Zeichen gefunden
        std::size_t anzahl; //size_t übergibt Wert oder stringlänge von Anz_Var an Variable anzahl???
        char dummy; // das Lesen des 'dummy' garantiert, das sich der Lesezeiger in der Kommenatrzeile befindet 
        if( (in >> anzahl >> dummy)
                .ignore( std::numeric_limits< std::streamsize >::max(), '\n' ) ) // Kommentar überlesen
        {
            std::vector< Foo > dreiD; //erzeugt Vektor mit datentyp/Structur Foo mit namen dreiD?
            dreiD.reserve( anzahl );    // optional, reserviert ein Minimum an Speicher von anzahl für den Vector dreiD 
            for( Foo x; anzahl && in >> x; --anzahl ) //Führe aus (Structur x; ?????; Zähle anzahl runter 
                dreiD.push_back( x );//fülle Vektor dreiD mit x vom Structurtyp foo
            if( in ) // wenn in != o dann 
                swap( dreiD, dreiD_ );  // ok; dann übernehmen,   swap tauscht Werte von Object dreiD zu dreiD_ , Warum?????
        }
        return in; gib in zurück, warum???
    }
    
    int main()
    {
        using namespace std;
        vector< Foo > dreiD;
        ifstream file( "/smb_mnt/tgutjahr/p/groupdrives/oe624-lsk/Aktuell/dipl/08-gutjahr/programme/Optimierungsprogramm/Testprogramme/test.txt" );
        if( !file.is_open() )
        {
            cerr << "Fehler beim Oeffnen" << endl;
            return -1;
        }
        if( read3DArray( file, dreiD ) )
        {
            cout << "alles klar!" << endl;
        }
    };
    

    Was bedeutet das "&" in Zeilen wie dieser?

    std::istream& Char( std::istream& in )
    

    Ist das eine Referenz? Welchen Sinn hat das?

    Viele Grüße

    Torsten



  • warum nimmst du keine cpp-tags? das wär vll für c++-quelltext gar ne so doof ^^

    ja, ist ne referenz...

    std::istream& Char( std::istream& in )
    

    hier wird immer nur eine Referenz kopiert... (ist so was wie ein Pointer)

    std::istream Char( std::istream in )
    

    So geht es zwar auch, aber jedes mal wird der istream (unnötig) kopiert...

    bb



  • Streams können nicht kopiert werden 😉



  • stanmc schrieb:

    Wozu ist das "Char<';'>" gut? Danke.

    Das dient ausschließlich dazu, ein Semikolon einzulesen und - falls da kein Semikolon kommt - den Stream in den Fehlerstatus zu setzen.
    Also wenn man z.B.: schreibt

    int i1, i2;
        if( cin >> i1 >> Char<';'> >> i2 )
        {
            // i1 und i2 wurden gelesen
            // und es stand mit Sicherheit ein Semikolon dazwischen
    

    dann kann man im Gutfall sicher sein, dass das Format im Stream so ist, wie es spezifiziert wurde.

    Siehe dazu auch hier mit 'trenner' oder hier mit 'sep'.

    Gruß
    Werner



  • guddy schrieb:

    hab mir das ganze nochmal reingezogen und einiges verstanden, denk ich. Ich hab mal Kommentare in den Quelltext geschrieben. Vielleicht könnt ihr mir Feedback geben ob ich das richtig vestehe oder nicht. ...

    Hallo Torsten,

    aus Deinen Fragen schließe ich, dass ich bei Dir ziemlich weit vorn anfangen muss. Ich werde das hier nur kurz beantworten. Vielleicht schlägst Du die Themen nochmal zusätzlich in der Dir verfügbaren Literatur nach.

    guddy schrieb:

    struct Foo
    {
        int m_var, m_uGrenze, m_oGrenze;
    };
    std::istream& operator>>( std::istream& in, Foo& x ) //formatierter input (was bedeuten die Werte in den Klammern? in=Name des iputstream?? und Ausgabe in x??
    {
        return in >> x.m_var >> Char<';'> >> x.m_uGrenze >> Char<';'> >> x.m_oGrenze; //gibt Werte des inputstream in zurück aber ohne ";"? und zwar in die Variablen der Strucktur x?
    }
    

    In C++ ist ein Ausdruck wie

    a = b + c;
    

    eine Funktion. Das ist ein Funktion mit zwei Parametern, was man auch so schreiben könnte:

    a = operator+( int a, int b );
    

    D.h. die Funktion heißt 'operator+' und hat die beiden Parameter 'a' und 'b' und das Ergebnis - also den Returnwert der Funktion - weise ich hier 'c' zu.

    Das kann man für fast alle Operatoren machen. Z.B. für den operator>>. Also statt zu schreiben

    std::istream& lese_Foo_ein( std::istream& in, Foo& x )
    

    schreibt man

    std::istream& operator>>( std::istream& in, Foo& x )
    

    . Das Ziel ist es nachher beim Aufruf einfach

    Foo x;
        cin >> x;
    

    zu schreiben. Genauso wie man a+b und nicht addiere( a, b ) schreiben möchte.

    Durch die Rückgabe der Referenz auf den Stream - und das muss(!) der selbe Stream sein wie der der übergeben wurde - erreicht man, dass man die Eingaben hintereinander schreiben kann. Etwa so

    Foo x, y, z;
        cin >> x >> y >> z;
    

    guddy schrieb:

    std::istream& read3DArray( std::istream& in, std::vector< Foo >& dreiD_ ) //Definier von istream abgeleitete Funktion read3DArray mit inputstreamquelle  in und Ziel vector dreiD_ mit daten-bzw. structurtyp Foo 
    {
        in.ignore( std::numeric_limits< std::streamsize >::max(), ':' ); // ignore(streamlänge, Zeichen) ignoriert Strom bis zu dem Punkt, wenn Streamlänge erreicht oder Zeichen gefunden
        std::size_t anzahl; //size_t übergibt Wert oder stringlänge von Anz_Var an Variable anzahl???
        char dummy; // das Lesen des 'dummy' garantiert, das sich der Lesezeiger in der Kommenatrzeile befindet 
        if( (in >> anzahl >> dummy)
                .ignore( std::numeric_limits< std::streamsize >::max(), '\n' ) ) // Kommentar überlesen
        {
            std::vector< Foo > dreiD; //erzeugt Vektor mit datentyp/Structur Foo mit namen dreiD?
            dreiD.reserve( anzahl );    // optional, reserviert ein Minimum an Speicher von anzahl für den Vector dreiD 
            for( Foo x; anzahl && in >> x; --anzahl ) //Führe aus (Structur x; ?????; Zähle anzahl runter 
                dreiD.push_back( x );//fülle Vektor dreiD mit x vom Structurtyp foo
            if( in ) // wenn in != o dann 
                swap( dreiD, dreiD_ );  // ok; dann übernehmen,   swap tauscht Werte von Object dreiD zu dreiD_ , Warum?????
        }
        return in; gib in zurück, warum???
    }
    

    Eine Funktion kann man nicht ableiten. Das gilt nur für Klassen bzw. Strukturen. readArray ist einfach eine Funktion mit zwei Parametern. Beide Parameter werden als - nicht const - Referenz übergeben; d.h. man kann die Werte ändern, die außerhalb der Funktion deklariert werden.

    Die Funktion von ignore hast Du richtig verstanden -es wird bis zum Doppelpunkt inklusive alles überlesen.

    size_t ist ein Typ wie int. Ich hätte auch 'int anzahl;' schreiben können. Nur der Standard gibt vor die Anzahl der Elemente in einem Container als std::size_t zu deklarieren. Denke einfach es wäre ein int, dann passt das.

    dreiD und reserve passt.

    Du kennst sicher for-Schleifen in der Art

    for( int i = 0; i < 5; ++i )
    

    Genauso wie dort ein int namens 'i' angelegt wird, habe ich bei mir ein Foo namens 'x' angelegt - ist genau das selbe.

    Im mittleren Teil steht eine Bedingung, also ein Ausdruck der in ein bool konvertiert werden kann. Einmal ist es 'i < 5' d.h. die Schleife wird solange durchlaufen solange i kleiner als 5 ist - in meinem Fall ist es eine UND-Bedingung d.h. beide Ausdrücke rechts und links von '&&' müssen 'true' sein, damit die Schleife durchlaufen wird.

    Links steht 'anzahl' - das ist true solange anzahl ungleich 0 ist. Und rechts steht in >> x. Das ist das Einlesen eines Foo-Objekts namens 'x' vom Input 'in'. Wie schon oben beschrieben gibt das eine std::istream& zurück. Diese Referenz ist in bool konvertierbar und liefert ein 'true' zurück, solange der Stream keinen Lesefehler hat.
    Wichtig ist noch - der zweite also rechte Ausdruck eines '&&' wird nur genau dann ausgeführt, wenn der erste bereits 'true' ist. D.h. wenn die 'anzahl' bei 0 ankommt, wird auch kein x mehr vom stream gelesen. Das ist wichtig, weil im Stream keines mehr kommt und man vielleicht danach noch etwas anderes aus dem Stream lesen möchte.

    Das swap hat den Zweck die gelesenen Daten in 'dreiD' nach 'dreiD_' zu schaufeln, denn das ist ja der Parameter, der per Referenz übergeben wurde und der soll ja geändert bzw. gefüllt werden.

    Gruß
    Werner



  • KasF schrieb:

    Insbesondere die Idee mit dem Char<';'> gefällt mir außerordentlich gut

    Mir nicht. Damit kannst du nicht mal den Nutzer die Möglichkeit anbieten, dass der Separator optional gewählt werden kann, weil eine Änderung bei Templates nur mit neukompileren möglich ist. Eine einfache Funktion mit Parameter wäre da komfortabler und flexibler. Außerdem sollte man den gleichen Separator auch nicht X mal im Code verteilen, sondern als Konstante halten.

    @guddy
    Hier mal ein Lösungsansatz der deinem Niveau entspricht.

    int main()
    {
    	std::ifstream file( "C:/tmp/input.txt" );
        if( !file.is_open() )
        {
            std::cerr << "Fehler beim Oeffnen" << std::endl;
            return -1;
        }
        file.ignore( std::numeric_limits< std::streamsize >::max(), ':' );
    	size_t arraySize;
    	file >> arraySize;
    
    	std::string comment;
    	file >> comment; //geht hier so einfach, da Var_nr;uGrenze;oGrenze ein Wort ist
    
    	int varNr, uGrenze;
    	char separator;
    	//Hier noch ein array erstellen und ne Schleife rum
    	file >> varNr >> separator >> uGrenze; // usw...
    };
    

    Fehlerprüfung kannst/musst du auch noch einbauen und wenn du willst noch ein paar structs und Funktionen zur Übersichlichkeit.



  • Hallo,

    ich hab mal "mal einfach"s Variante probiert, weil sie mir einfacher erscheint.
    Ich hab deine Anweisungen befolgt, aber der compiler spuckt einige folgender Fehlermeldungen aus:

    C:29: error: no match for 'operator>>' in 'file.std::basic_ifstream<char, std::char_traits<char> >::<anonymous>.std::basic_istream<_CharT, _Traits>::operator>> [with _CharT = char, _Traits = std::char_traits<char>](((int&)(& varNr))) >> separator'
    

    Kann es sein, dass die datentypen nicht übereinstimmen? im stream stehen ja eigentlich string oder char. Ich habe aber oGrenze, usw. als int definiert. Wenn ich sie jedoch als char definiere kommen ähnliche fehler...
    Wo leigt der Fehler?

    Der Quellcode:

    #include <iostream>
    #include <fstream>
    
    int main()
    {
    
        std::ifstream file("Variableninput.dat");
        if( !file.is_open() )
        {
            std::cerr << "Fehler beim Oeffnen" << std::endl;
            return -1;
        }
        file.ignore( std::numeric_limits< std::streamsize >::max(), ':' );
        size_t arrayHeigth;
        file >> arrayHeigth;
    
        std::string comment;
        file >> comment; //geht hier so einfach, da Var_nr;uGrenze;oGrenze ein Wort ist, ansonsten: file.ignore( std::numeric_limits< std::streamsize >::max(), '\n' ) )
    
        int varNr, uGrenze, oGrenze, arrayWidth;
        const char* separator = ";";
        //Hier noch ein array erstellen und ne Schleife rum
        int varArray[arrayHeigth] [arrayWidth];
        arrayWidth = 3;
    
        for (unsigned int i = 1; i <= arrayHeigth; i++)
        {	    
        file >> varNr >> separator >> uGrenze >> separator >> oGrenze >> "\n";
        varArray [i] [1] = varNr; varArray [i] [2] = uGrenze; varArray [i] [3] = oGrenze;
        std :: cout << varArray [i] [1] << "\t" << varArray [i] [2] << "\t" << varArray [i] [3]<< "\n";
        }
    }
    


  • Hallo Leute,

    ich hab mal Werners Code probiert und ihn auch einigermaßen verstanden. Ich möchte nun noch ein paar Änderungen vornehmen. Die Inputdatei sieht jetzt wie folgt aus:

    Prozessname: Rankine
    Datum oder Zifferncodierung: 66
    GA-Typ: 1
    Genome-Typ: 2
    Testfunktionstyp: 1 
    Anzahl der Durchläufe: 100 
    Anzahl der Variablen:3
    
    Var_nr;uGrenze;oGrenze
    1;5;50
    2;44;450
    3;55;500
    

    In der alten Datei wurden nur die Anzahl der Variablen eingelesen.

    Wie kann ich Werners Code abändern um die Werte nach ":" als char (bei Prozessname, Datum oder Ziffern) und als int (bei GA-Typ, testfunktion und Anzahl der durchläufe) abzuspeichern?

    Hier nochmal der Code:

    #include <iostream>
    #include <fstream>
    #include <vector>
    #include <limits>
    
    template< char C >
    std::istream& Char( std::istream& in )
    {
        char c;
        if( in >> c && c != C )
            in.setstate( std::ios_base::failbit );
        return in;
    }
    
    struct Foo
    {
        int m_var, m_uGrenze, m_oGrenze;
    
    };
    
    std::istream& operator>>( std::istream& in, Foo& x ) //formatierter input (was bedeuten die Werte in den Klammern? in=Name des iputstream?? und Ausgabe in x??
    {
        return in >> x.m_var >> Char<';'> >> x.m_uGrenze >> Char<';'> >> x.m_oGrenze; //gibt Werte des inputstream in zurück aber ohne ";"? und zwar in die Variablen der Strucktur x?
    }
    
    std::istream& read3DArray( std::istream& in, std::vector< Foo >& dreiD_ ) //Definier von istream abgeleitete Funktion read3DArray mit inputstreamquelle  in und Ziel vector dreiD_ mit daten-bzw. structurtyp Foo 
    {
    
        in.ignore( std::numeric_limits< std::streamsize >::max(), ':' ); // ignore(streamlänge, Zeichen) ignoriert Strom bis zu dem Punkt, wenn Streamlänge erreicht oder Zeichen gefunden
    
        std::size_t anzahl; //size_t übergibt Wert oder stringlänge von Anz_Var an Variable anzahl???
        char dummy; // das Lesen des 'dummy' garantiert, das sich der Lesezeiger in der Kommenatrzeile befindet 
        if( (in >> anzahl >> dummy)
                .ignore( std::numeric_limits< std::streamsize >::max(), '\n' ) ) // Kommentar überlesen
        {
            std::vector< Foo > dreiD; //erzeugt Vektor mit datentyp/Structur Foo mit namen dreiD?
            dreiD.reserve( anzahl );    // optional, reserviert ein Minimum an Speicher von anzahl für den Vector dreiD 
            for( Foo x; anzahl && in >> x; --anzahl ) //Führe aus (Structur x; ?????; Zähle anzahl runter 
                dreiD.push_back( x );//fülle Vektor dreiD mit x vom Structurtyp foo
            if( in ) // wenn in != o dann 
                swap( dreiD, dreiD_ );  // ok; dann übernehmen,   swap tauscht Werte von Object dreiD zu dreiD_ , Warum?????
        }
        return in; //gib in zurück, warum???
    }
    
    int main()
    {
        using namespace std;
        vector< Foo > dreiD;
        char prozessname[256]; 	
        ifstream file( "Variableninput.dat" );
        if( !file.is_open() )
        {
            cerr << "Fehler beim Oeffnen der Datei Variableninput" << endl;
            return -1;
        }
        if( read3DArray( file, dreiD, prozessname) )
        {
            cout << "Vector eingelesen" << endl;
    	cout << dreiD[1].m_var << endl;;
        }
    }
    

    Danke für eure Hilfe.


Anmelden zum Antworten