Zahlen aus TXT-Datei in Vektor abspeichern



  • Guten Tag, liebe C++-Community!
    Ich habe folgendes Problem: Undzwar bin ich in Sachen C++-Programmierung noch ein ziemlicher Anfänger.
    Ich möchte aus einer *.txt-Datei, welche zB wie folgt aussieht:

    zeile1 1 2 3 4 5 6
    zeile2 3 4 5 6 7 8 9

    nur die einzelnen Zahlenwerte einlesen und diese möglichst als Vektor abspeichern, so dass ich dann wieder auf jede einzelne Zahl zugreifen kann und diese widerrum für Rechenoperationen verwenden kann, beispielsweise die ersten drei Zahlen aus "zeile1" geteilt durch die letzten drei aus "zeile1"...

    Mir ist schon bekannt, wie ich Dateien mittels ifstream einlese, jedoch weiß ich jetzt nicht wie ich die Bezeichnung für jede Zeile weglassen kann und dann die restlichen Zahlen abspeichere. Deswegen hoffe ich auf eure Hilfe... 😞

    Einen schönen Tag noch!

    CppNoob3 🙂



  • Bin zwar nicht der beste Programmierer, aber vielleicht hilft dir dieses Beispiel:

    #include <vector>
    #include <string>
    #include <iostream>
    #include <fstream>
    
    int main()
    {
    	std::ifstream file("test.text");
    
    	if(!file)
    	{
    		return 1;
    	}
    
    	std::vector<std::vector<int>> values;
    
    	whil(file)
    	{
    		std::string line;
    		file >> line;
    		std::cout << line << "\n";
    
    		int value;
    		values.push_back(std::vector<int>());
    
    		while ((file.peek()!='\n') && (file>>value))
    		{
    			values.back().push_back(value);
    		}
    	}
    
    	for(const auto& vec : values)
    	{
    		for(const auto value : vec)
    		{
    			std::cout << value << ", ";
    		}
    		std::cout << "\n";
    	}
    }
    

  • Mod

    int64 schrieb:

    Bin zwar nicht der beste Programmierer, aber vielleicht hilft dir dieses Beispiel:

    Teste deinen Vorschlag mal mit mehr als einer Zeile!



  • ich würde hier zu getline() greifen und mir vielleicht mal die stringstreams näher anschauen


  • Mod

    Sewing schrieb:

    ich würde hier zu getline() greifen und mir vielleicht mal die stringstreams näher anschauen

    Und mit dem Stringstream machst du dann was? Wahrscheinlich doch genau das gleiche, was du auch ohne Umweg direkt mit dem Filestream hättest machen können.



  • Ich bedanke mich erstmal für eure Antworten!

    Ich habe bereits mittels ifstream die Datei eingelesen.
    @SeppJ meinst du das?
    Ein Rätsel bleibt mir trotzdem noch, wie ich jetzt an die Zahlen komme...



  • SeppJ schrieb:

    Und mit dem Stringstream machst du dann was? Wahrscheinlich doch genau das gleiche, was du auch ohne Umweg direkt mit dem Filestream hättest machen können.

    Den Stringstream kann man lesen bis er "zu ende" ist. Dann hat man eine Zeile fertig, und kann die nächste mit getline holen. Rinse, repeat.

    Wie man genau das gleiche ohne Stringstream macht wüsste ich nicht. Nichtmal wie man überhaupt halbwegs schön und einfach zeilenbasierte Files ohne getline einliest.


  • Mod

    hustbaer schrieb:

    SeppJ schrieb:

    Und mit dem Stringstream machst du dann was? Wahrscheinlich doch genau das gleiche, was du auch ohne Umweg direkt mit dem Filestream hättest machen können.

    Den Stringstream kann man lesen bis er "zu ende" ist. Dann hat man eine Zeile fertig, und kann die nächste mit getline holen. Rinse, repeat.

    Wie man genau das gleiche ohne Stringstream macht wüsste ich nicht. Nichtmal wie man überhaupt halbwegs schön und einfach zeilenbasierte Files ohne getline einliest.

    In diesem konkreten Fall ist es einfach, da das Format auch als Zahlenreihen mit Zeichenketten als Trennzeichen angesehen werden kann. Das ist also so zu lesen, wie int64 es vorgemacht hat, bloß dass er ein clear vergessen hat.

    Den allgemeinen Fall hat Werner Salomon hier unzählige Male demonstriert; konkrete Implementierungen findest du sicherlich, wenn du einfach zufällig ein paar Beiträge von ihm durchliest.



  • Ich vermute du meinst diesen Beitrag:
    https://www.c-plusplus.net/forum/p1940874#1940874

    Die darin enthaltene is_endl Funktion ist ja ziemlich praktisch und auch sehr elegant verwendbar.

    Hat mir Werner ja auch netterweise in diesem Thread verlinkt: https://www.c-plusplus.net/forum/316061

    Nur dass ich es immer noch nicht einfach oder intuitiv finde. Also die Verwendung schon, aber nicht sich die Funktion selbst zu schreiben. Jemanden der viel mit iostreams macht und sich auch viel damit beschäftigt hat mag das nicht beeindrucken, aber wie viele Neulinge oder auch nur iostream-Neulinge damit kämpfen sieht man ja anhand der Fragen die hier doch öfters auftauchen. Bzw. der Antworten, in denen dann fast immer (wenn sie nicht von Werner kommen) getline verwendet wird.

    ps: Wenn man davon ausgeht dass in dem Code von int64 ein clear fehlt, dann ist da wohl auch ein (sehr verwirrendes) file.peek()!='\n' zuviel... nicht? Und mit dem clear fehlt dann vermutlich nochmal ein Test ob der Stream noch "good" ist nach file >> line; .

    ps2: Und ja, ich hatte den Thread und die Funktion bereits wieder vergessen. Damit wären die Kriterien "schön und einfach" erfüllt, allerdings eben nur wenn man die is_endl bei der Ermittlung von "einfach" nicht berücksichtigt -- z.B. weil man sie schon hat oder einfach hier rauskopieren kann 😃


  • Mod

    hustbaer schrieb:

    Nur dass ich es immer noch nicht einfach oder intuitiv finde. Also die Verwendung schon, aber nicht sich die Funktion selbst zu schreiben. Jemandem der viel mit iostreams macht und sich auch viel damit beschäftigt hat mag das nicht beeindrucken, aber wie viele Neulinge oder auch nur iostream-Neulinge damit kämpfen sieht man ja anhand der Fragen die hier doch öfters auftauchen. Bzw. der Antworten, in denen dann fast immer (wenn sie nicht von Werner kommen) getline verwendet wird.

    Und man sollte den Anfängern nicht erklären, dass es auch besser ginge?

    ps: Wenn man davon ausgeht dass in dem Code von int64 ein clear fehlt, dann ist da wohl auch ein (sehr verwirrendes) file.peek()!='\n' zuviel... nicht? Und mit dem clear fehlt dann vermutlich nochmal ein Test ob der Stream noch "good" ist nach file >> line; .

    Das war keine Detailkritik an dem Beitrag von int64, sondern nannte nur den groben Logikfehler. Wenn es unbedingt sein muss, hier eine Musterlösung:

    vector<vector<int> > values;
      for(std::string word; cin >> word;)
        {
          values.emplace_back();
          for(int value; cin >> value;)
            {
              values.back().push_back(value);
            }
          cin.clear();
        }
    

    Ist doch nicht wirklich kompliziert, oder?



  • SeppJ schrieb:

    Und man sollte den Anfängern nicht erklären, dass es auch besser ginge?

    Klar sollte man das. Nur vielleicht auch so dass auch ein Anfänger 'was damit anfangen kann.



  • Danke an SeppJ für die moralische Unterstützung.
    Ich kann aber auch die Argumentation von hustbaer nachvollziehen. Es gibt schlicht keine einfache 'out-of-the-standard'-Lösung für genau dieses Problem.

    Was haltet Ihr denn davon, wenn das is_endl - bzw. etwas entsprechendes - Teil des Standards würde?

    Gruß
    Werner



  • Ich bin jetzt verwirrt. Soll die Datei so aussehen:

    zeile1 1 2 3 4 5
    zeile2 6 7 8 9 10
    

    oder so

    1 2 3 4 5
    6 7 8 9 10
    

    Bin da jetzt persönlich nicht ganz im Klaren...



  • Werner Salomon schrieb:

    Was haltet Ihr denn davon, wenn das is_endl - bzw. etwas entsprechendes - Teil des Standards würde?

    👍

    Das einzige wo ich nicht ganz glücklich drüber bin ist der Name. Weil "is" nahelegt dass kein State modifiziert wird. Der "skipws" Teil der Angelegenheit stört mich weniger, dass "is_endl" den Linebreak frisst dagegen schon.
    Nach unseren Konventionen würde ich das Ding vermutlich "TryReadLineBreak" nennen.

    Aber "try_read_xxx" - klingt nicht sehr Standardesisch. Und nur "read_endl" für ne Funktion die bool zurückliefert... hm. Weiss nicht.

    Evtl. könnte man eine "is" Funktion zusätzlich anbieten, die wirklich nur (wenn "skipws") die Whitespaces frisst, den Linebreak aber im Puffer stehen lässt.


  • Mod

    dass "is_endl" den Linebreak frisst dagegen schon.

    Was willst du denn damit?

    Ich wäre für skip_endl . Kann man aber alles im Paper auflisten, falls man es schreibt.



  • Arcoth schrieb:

    dass "is_endl" den Linebreak frisst dagegen schon.

    Was willst du denn damit?

    Die Frage ist erstmal nicht was ich damit will, sondern ob der Name was verspricht was er nicht hält.

    Und was ich damit will? Vielleicht verschachtelte Schleifen abbrechen?

    void process_line()
    {
       ...
       while (!is_endl(s))
       {
          ...
          while (!is_endl(s) && ...)
             ...
       }
    
       read_endl(s);
    }
    

    Arcoth schrieb:

    Ich wäre für skip_endl . Kann man aber alles im Paper auflisten, falls man es schreibt.

    Wäre net schlecht wenn da nicht skipws wäre was aber ganz was anderes tut. Aber ja, die Alternativen kann man im Paper auflisten. Ich wollte nur trotzdem hier darauf hinweisen, da ich das Paper sicher nicht schreiben werden. Dafür fehlt mir echt die Erfahrung mit den iostreams, und ich hatte das auch so verstanden dass Werner sich überlegt es zu schreiben.


  • Mod

    Die Frage ist erstmal nicht was ich damit will, sondern ob der Name was verspricht was er nicht hält.

    skip_endl heißt buchstäblich "überspringe den Zeilenumbruch".

    Dafür fehlt mir echt die Erfahrung mit den iostreams

    Den Code hast du ja, brauchst Werner nur zu danken (buchstäblich, im Acknowledgement Teil). Der Rest ist Motivation, die deutlich wichtiger ist als der Code. Der Code ist vergleichsweise trivial und wird von jeder Implementierung sowieso selbst geschrieben werden. Damit LEWG dem Ganzen jedoch positiv gestimmt sein soll, muss überzeugt werden, dass ein Bedürfnis nach dieser Funktion besteht, das nicht nur von dir in irgendeinem Projekt, sondern von einem signifikanten Teil der Gemeinde ausgeht.

    Und was ich damit will? Vielleicht verschachtelte Schleifen abbrechen?

    Aha, also hilft's in einem Fall. In allen anderen interessiert mich dieses Newline nicht, und ich muss es manuell rausschmeißen.

    Wäre net schlecht wenn da nicht skipws wäre was aber ganz was anderes tut.

    skipws ignoriert den Leerraum. skip_endl ignoriert Leerraum bis und inklusive des ersten Newlines. Zugegeben, skip_until_endl wäre womöglich besser.

    Edit^x:
    Dein Code lässt sich mittels loops with exit strategies umschreiben:

    void process_line()
    {
       ...
       while (true)
       {
          ...
          if while (!skip_until_endl(s)) {
             if (...) break;
             ...
          }
          break;
          else;
       }
    
       read_endl(s);
    }
    

    Ist auch performanter AFAICS.


Log in to reply