Zahlen aus txt auslesen und in array speichern



  • Hey Leute,

    ich habe vor einem Jahr schon ein wenig mit C++ gearbeitet aber hab leider alles wieder vergessen und komme jetzt wo ich es brauche nicht weiter.

    Das Problem:

    Ich habe eine .txt Datei die wie folgt aufgebaut ist:

    0, 0.3245
    0, 0.5566
    .
    .
    0, 0.9598
    undef, undef
    1, 0.0945
    1, 0.8748
    .
    .
    1, 0.8789
    undef, undef
    2, 0.035
    2, 0.9545
    .
    .
    .
    usw.

    Ich würde gerne folgendes erreichen: die letzten Werte vor dem undef, undef (also z.B. 0 und 0.9598) immer in ein Array abspeichern um sie später verwenden zu können; .

    Ich habe wirklich keine Ahnung wie ich das anstellen soll, außer das man dazu ifstream braucht.

    Bitte um Hilfe, ich bin hier echt am verzweifeln.
    Gruß



  • string gesucht = "undef, undef";
    

    Du liest zwei Zeilen ein, in zwei verschiedene strings .
    Quasi die erste Zeile in den string zeile1 und die darauf folgende in den string zeile2 , immer abwechselnd.

    Sobald

    strcmp(zeile1, gesucht) == 0
    

    oder

    strcmp(zeile2, gesucht) == 0
    

    hast du automatisch die Zeile davor in der anderen string-Variable gespeichert und kannst sie für deine Zwecke verwenden.

    Als Denkanstoß verlinke ich diese Seite.





  • Die C++ Lösung lautet aber

    if (zeile == gesucht)
    {
       // ...
    }
    

    Als Tipp noch: zum Einlesen von Zeilen std::getline(input, line) verwenden.



  • phanzy schrieb:

    Sobald

    strcmp(zeile1, gesucht) == 0
    

    oder

    strcmp(zeile2, gesucht) == 0
    

    hast du automatisch die Zeile davor in der anderen string-Variable gespeichert und kannst sie für deine Zwecke verwenden.

    Und Strings vergleicht man mit == und nicht mit strcmp, wir sprechen C++ und nicht C.



  • Th69 schrieb:

    Die C++ Lösung lautet aber

    if (zeile == gesucht)
    {
       // ...
    }
    

    Und wenn true , wie willst du dann den Inhalt der Zeile darüber erhalten?


  • Mod

    phanzy schrieb:

    Und wenn true , wie willst du dann den Inhalt der Zeile darüber erhalten?

    Den Inhalt kennen wir doch, der ist 'undef, undef'.

    Nachdem man das gefunden hat, geht man zwei Zeilen zurück, und liest die beiden Zahlen ein.



  • Hallo Skym0sh0,

    warum hast du mich zitiert? Ich bezog mich auf den Beitrag von @phanzy (du hast nur ein paar Sekunden vorher deinen Beitrag abgeschickt und das konnte ich ja nicht wissen).



  • Oh, ja du hast recht. Irgendwie verpennt oO
    Habs geändert. 🙂



  • Wie kann man "einfach zwei Zeilen zurück" gehen?
    Das funktioniert nämlich meines Wissens nicht.
    Außerdem müsste man nur "eine Zeile zurück"...

    @Skym0sh0 Stimmt, hab ich übersehn.


  • Mod

    Außerdem müsste man nur "eine Zeile zurück"...

    Ich wusste, dass das kommt. Nein, man muss zwei Zeilen zurück.

    Wie kann man "einfach zwei Zeilen zurück" gehen? Das funktioniert nämlich meines Wissens nicht.

    Meines Wissens schon.



  • Hallo phancy,

    man kann sich doch einfach immer die letzte Zeile merken.
    Da Code mehr sagt als 1000 Worte:

    ifstream is("file.txt");
    
    const string undef_line = "undef, undef";
    
    string line, last_line;
    while (getline(is, line))
    {
      if (line == undef_line)
      {
        // use last_line
        // ...
      }
    
      last_line = line;
    }
    

    (ungetestet)


  • Mod

    Dan muss man diese Zeile aber wiederum in einen Stringstream stopfen und beide Zahlen extrahieren...



  • @*
    Wie willst du eine gewisse Anzahl an Zeilen zurück "gehen"? Zeig doch mal ein wenig Code, ich bezweifle nämlich, dass das funktioniert.

    @Th69
    phanzy mit z 👍
    Wenn du meine erste Antwort ansiehst merkst du, dass ich das eh weiß und auch vorgeschlagen habe 😉


  • Mod

    Nun, du nutzt unget() bis du da ankommst.
    Mache gleich mal ein Beispiel mit Stringstream.





    • schrieb:

    Nun, du nutzt unget() bis du da ankommst.

    Danke, das kannte ich bisher nicht. 😉



  • phanzy schrieb:

    • schrieb:

    Nun, du nutzt unget() bis du da ankommst.

    Danke, das kannte ich bisher nicht. 😉

    Ist auch besser so, unget funktioniert nicht. Das kann jederzeit fehlschlagen und dann bist du so klug wie vorher.

    Tip: Ignoriere *.


  • Mod

    Ja, unget() funktioniert nicht, da der Buffer nicht groß genug sein muss, um alle Zeichen aus der vorigen Zeile zu halten. Stattdessen kann man einfach die aktuelle Position zwischenspeichern (per tellg()) und anschließend dahin zurückspringen.

    #include <iostream>
    #include <sstream>
    
    int main()
    {
    	std::istringstream stream(" 4 8 \n"
    	                          " 8 456\n"
    	                          "12 536\n"
    	                          "undef, undef");
    
    	std::string str;
    	std::streampos pos = -1, current = 0;
    
    	while( std::getline(stream, str) && str != "undef, undef" )
    	{
    		pos = current;
    		current = stream.tellg();
    	}
    
    	if( pos != -1 )
    	{
    		stream.seekg(pos);
    		int a, b;
    		stream >> a >> b;
    		std::cout << a << ' ' << b << '\n';
    	}
    }
    


  • ArtiTT schrieb:

    Ich habe eine .txt Datei die wie folgt aufgebaut ist:

    0, 0.3245
    0, 0.5566
    .
    .
    0, 0.9598
    undef, undef
    1, 0.0945
    1, 0.8748
    .
    .
    1, 0.8789
    undef, undef
    2, 0.035
    2, 0.9545
    .
    .
    .
    usw.

    Ich würde gerne folgendes erreichen: die letzten Werte vor dem undef, undef (also z.B. 0 und 0.9598) immer in ein Array abspeichern um sie später verwenden zu können; .

    Hallo ArtiTT,

    ich unterstelle mal, dass - wenn die Datei so aussieht wie oben - in dem Array später folgendes 2 Einträge stehen sollen:

    0, 0.9598
    1, 0.8789
    

    Weiter unterstelle ich, dass die erste Zahl ein Integer und die zweite eine Fließkommazahl ist.

    Zunächst mal liest man Zahlenwerte wie Integer und Fließkomma so, wie es Skym0sh0 schon gezeigt hat - siehe auch operator>>. Jetzt muss man nur noch ein wenig Code schreiben, der das 'undef, undef' erkennt und dann speichert man sich den zuletzt gelesen Eintrag (bestehend aus int und double) in dem Array ab.
    Das ist schon alles.

    Das ganze könnte etwa so aussehen:

    #include <iostream>
    #include <fstream>
    #include <vector>
    #include <limits> // numeric_limits
    
    struct EineStruct
    {
        EineStruct()
            : id(), number()    // Defaultkonstruktor sorgt für definierte Daten
        {}
        int id;
        double number;
    };
    // --   Funktion zum Einlesen einer Struktur 'EineStruct'
    //      Format "<int>, <double>"
    std::istream& operator>>( std::istream& in, EineStruct& s )
    {
        char komma;
        if( in >> s.id >> komma && komma != ',' )
            in.setstate( std::ios_base::failbit ); // Formatfehler -> dann fail
        return in >> s.number; 
    }
    
    int main()
    {
        using namespace std;
        vector< EineStruct > ein_array;
        ifstream datei("eineDatei.txt");
        if( !datei.is_open() )
        {
            cerr << "Fehler beim Oeffnen der Datei" << endl;
            return -2;
        }
        for( EineStruct eintrag; datei; )
        {
            char c;
            if( datei >> c && c == 'u' ) // "undef, undef"
            {
                ein_array.push_back( eintrag ); // zuletzt gelesenen Eintrag speichern da jetzt 'undef, undef' folgt
                datei.ignore( numeric_limits< streamsize >::max(), '\n' ); // überspringe diese Zeile
            }
            else 
                datei.putback( c ) >> eintrag; // Character 'c' wieder zurück stellen und Eintrag zunächst nur lesen
        }
        if( datei.eof() ) // EOF erreicht -> alles iO
        {
            cout << "es sind " << ein_array.size() << " Eintrage gelesen worden" << endl;
            // ... usw.
        }
        return 0;
    }
    

    Gruß
    Werner


Anmelden zum Antworten