Konsolenproblem



  • Belli schrieb:

    vollständig qualifizierten

    Du meinst absoluten 😃



  • Du hast zumindest schon mal richtig erkannt, dass ein nicht absoluter Pfad nicht vollständig ist.
    Ansonsten weiß ich ja jetzt, wen ich in Zukunft fragen kann, wenn ich mal nicht weiß, was ich meine.



  • PDD31 schrieb:

    // ...
        // Solange noch Daten vorhanden sind wird die Schleife ausgeführt
        while (!file.eof()) 
    	{
            // ...
    	}
    // ...
    

    Kommentar und Code passen nicht zusammen.
    Aber der Fehler ist weitverbreitet und taucht hier immer wieder auf.

    Heute möchte ich eine neue Form ausprobieren, um Dir das auszutreiben! 😉

    Um zu zeigen, warum Du input so einlesen solltest, wie z.B. Sone es vorschlägt, hier ein hoffentlich nicht zu schräger Vergleich mit dem sprichwörtlichen Krug, der solange zum Brunnen geht, bis er bricht (http://de.wiktionary.org/wiki/Der_Krug_geht_so_lange_zum_Brunnen,_bis_er_bricht).

    Ich denke Du erkennst die Parallelen zum std::istream , und warum die erste Variante gehe_zum_brunnen() einmal häufiger aufruft als nötig:
    - ein istream setzt das eofbit , wenn eine input operation das Ende der Eingabe erreicht hat.
    - ein Krug setzt das ist_gebrochen_ flag, wenn eine gehe_zum_brunnen() operation, das Ende seiner Lebenszeit erreicht hat.

    #include <iostream>
    
    class Krug{
    public:
      Krug(int max = 5) : max_fuellungen_(max), fuellungen_(0), ist_gebrochen_(false){}
      bool ist_gebrochen() const { return ist_gebrochen_; }
      /* gehe_zum_brunnen()
       * wenn der Krug noch gefuellt werden kann: fuellt den Krug
       * sonst:
       * setzt das ist_gebrochen_ flag und macht nichts
       * Return:
       * true wenn, der Krug gefuellt werden konnte, false sonst
       */
      bool gehe_zum_brunnen(){
        if( !(fuellungen_ < max_fuellungen_) ){
          ist_gebrochen_ = true;
          return false;
        }
        ++fuellungen_;
        return true;
      }
    private:
      int  max_fuellungen_;
      int fuellungen_;
      bool ist_gebrochen_;
    };
    
    int main(){
        Krug krug0, krug1;
        int i = 0, j = 0;
    
        /* Deine Variante: solange ist_gebrochen() false ist, gehe_zum_brunnen() und... */
        std::cout << "Du:\n";
        while(!krug0.ist_gebrochen()){
          std::cout << "gehe zum Brunnen.(" << i << ")\n";
          krug0.gehe_zum_brunnen();
          ++i;
        }
    
        std::cout << "\nIch:\n";
        /* Meine Variante: gehe_zum_brunnen() und wenn das klappt, dann... */
        while(krug1.gehe_zum_brunnen()){
          std::cout << "gehe zum Brunnen.(" << j << ")\n";
          ++j;
        }
    }
    

    Einleuchtend?
    🙂



  • Furble Wurble schrieb:

    PDD31 schrieb:

    // ...
        // Solange noch Daten vorhanden sind wird die Schleife ausgeführt
        while (!file.eof()) 
    	{
            // ...
    	}
    // ...
    

    Kommentar und Code passen nicht zusammen.
    Aber der Fehler ist weitverbreitet und taucht hier immer wieder auf.

    Heute möchte ich eine neue Form ausprobieren, um Dir das auszutreiben! 😉

    Um zu zeigen, warum Du input so einlesen solltest, wie z.B. Sone es vorschlägt, hier ein hoffentlich nicht zu schräger Vergleich mit dem sprichwörtlichen Krug, der solange zum Brunnen geht, bis er bricht (http://de.wiktionary.org/wiki/Der_Krug_geht_so_lange_zum_Brunnen,_bis_er_bricht).

    Ich denke Du erkennst die Parallelen zum std::istream , und warum die erste Variante gehe_zum_brunnen() einmal häufiger aufruft als nötig:
    - ein istream setzt das eofbit , wenn eine input operation das Ende der Eingabe erreicht hat.
    - ein Krug setzt das ist_gebrochen_ flag, wenn eine gehe_zum_brunnen() operation, das Ende seiner Lebenszeit erreicht hat.

    #include <iostream>
    
    class Krug{
    public:
      Krug(int max = 5) : max_fuellungen_(max), fuellungen_(0), ist_gebrochen_(false){}
      bool ist_gebrochen() const { return ist_gebrochen_; }
      /* gehe_zum_brunnen()
       * wenn der Krug noch gefuellt werden kann: fuellt den Krug
       * sonst:
       * setzt das ist_gebrochen_ flag und macht nichts
       * Return:
       * true wenn, der Krug gefuellt werden konnte, false sonst
       */
      bool gehe_zum_brunnen(){
        if( !(fuellungen_ < max_fuellungen_) ){
          ist_gebrochen_ = true;
          return false;
        }
        ++fuellungen_;
        return true;
      }
    private:
      int  max_fuellungen_;
      int fuellungen_;
      bool ist_gebrochen_;
    };
    
    int main(){
        Krug krug0, krug1;
        int i = 0, j = 0;
    
        /* Deine Variante: solange ist_gebrochen() false ist, gehe_zum_brunnen() und... */
        std::cout << "Du:\n";
        while(!krug0.ist_gebrochen()){
          std::cout << "gehe zum Brunnen.(" << i << ")\n";
          krug0.gehe_zum_brunnen();
          ++i;
        }
        
        std::cout << "\nIch:\n";
        /* Meine Variante: gehe_zum_brunnen() und wenn das klappt, dann... */
        while(krug1.gehe_zum_brunnen()){
          std::cout << "gehe zum Brunnen.(" << j << ")\n";
          ++j;
        }
    }
    

    Einleuchtend?
    🙂

    Ist einleuchtend 👍 🙂 werde mich bemühen es in Zukunft besser zu machen 🙂

    Belli schrieb:

    PDD31 schrieb:

    bzw wo ist das Verzeichnis zu finden?

    Das hängt davon ab, wie, bzw. mit welcher IDE Du Dein Programm erstellst ...
    Du kannst aber einfach den vollständig qualifizierten Pfad Deiner zu verarbeitenden Datei angeben, zB:

    ifstream file("C:\\tmp\\meinVerzeichnis\\Datei_2.txt");
    

    Danke Belli, jetzt funktioniert alles so wie gewollt 🙂



  • was muss ich tun, wenn ich jetzt erst ab Zeile 44, Stelle 23 meiner .txt Datei lesen will, da fehlt mir gerade die Idee.

    Ich hab den Code von Sone genommen:

    #include <iostream>
    #include <fstream>
    #include <string>
    
    using namespace std;
    
    void Load()
    {
        ifstream file("C:\\Users\\patrick.dahlke\\Documents\\SWProtokoll\\Datei_2.txt");		
    
        for(std::string text;getline(file, text);) 
            cout << text << '\n'; 
    
    } 
    
    int main(int argc, char **argv)
    {
        Load();
    	getchar();
    	getchar();
        return 0;
    }
    


  • PDD31 schrieb:

    was muss ich tun, wenn ich jetzt erst ab Zeile 44, Stelle 23 meiner .txt Datei lesen will, da fehlt mir gerade die Idee.

    Schau mal, ob das so klappt:

    #include <fstream>
    #include <iostream>
    #include <limits>
    #include <string>
    using namespace std;
    
    template<size_t N>
    istream& skip_line(istream& in)
    {
    	for(size_t i=0; i<N; ++i)
    		in.ignore( numeric_limits<streamsize>::max(), '\n' );
    	return in;
    }
    
    template<size_t N>
    istream& skip_char(istream& in)
    {
    	char c;
    	for(size_t i=0; i<N; ++i)
    		in >> noskipws >> c;
    	return in;
    }
    
    int main()
    {
    	ifstream file("test.txt");
    	file >> skip_line<43>;
    	file >> skip_char<22>;
    	for(string s; getline(file,s); cout<<s<<'\n');
    }
    


  • template<size_t N> 
    istream& skip_char(istream& in) 
    { 
        char c; 
        for(size_t i=0; i<N; ++i) 
            in >> noskipws >> c; 
        return in; 
    }
    

    😃

    template<size_t N> 
    istream& skip_char(istream& in) 
    { 
        return in.ignore(N);
    }
    

    Und eigentlich kann man das gleich schreiben.



  • 😃 😃 Was hab ich den da gemacht. Änder mal eine Funktion ab:

    template<size_t N>
    istream& skip_char(istream& in)
    {
    	return in.ignore( N );
    }
    


  • PDD31 schrieb:

    was muss ich tun, wenn ich jetzt erst ab Zeile 44, Stelle 23 meiner .txt Datei lesen will, da fehlt mir gerade die Idee.

    Das geht nicht, wenn die Zeilen unterschiedlich lang sind. Du musst dann einfach die ersten 43 Zeilen überlesen - das heißt, einlesen und nicht weiter verarbeiten - wenn Du die 44 Zeile eingelesen hast, erst mal feststellen, ob sie überhaupt 23 Zeichen hat, und dann halt die ersten 22 Zeichen aus Deinem String werfen und ab da dann weiter wie gehabt ...



  • Danke out und Sone,

    Belli schrieb:

    PDD31 schrieb:

    was muss ich tun, wenn ich jetzt erst ab Zeile 44, Stelle 23 meiner .txt Datei lesen will, da fehlt mir gerade die Idee.

    Das geht nicht, wenn die Zeilen unterschiedlich lang sind. Du musst dann einfach die ersten 43 Zeilen überlesen - das heißt, einlesen und nicht weiter verarbeiten - wenn Du die 44 Zeile eingelesen hast, erst mal feststellen, ob sie überhaupt 23 Zeichen hat, und dann halt die ersten 22 Zeichen aus Deinem String werfen und ab da dann weiter wie gehabt ...

    In dem Fall ist es so, dass die Datei in Zeile 44 immer mindesten 23 Stellen hat
    und das Gesuchte auch immer an dieser Stelle steht, also müsste das von out eigentlich passen 😃
    Danke 👍



  • Ich hab jetzt am Ende der Datei noch ziemlich viel Müll, zwischendrin eine Zeile die ich brauche und ganz am Ende nochmal eine wichtige Zeile.

    Wie kann ich jetzt die Zeilen dwischendrin rausschmeisen?

    Kennung der Zeilen die nich die Zeilenzahl sondern ein Wort.
    Ich hab sowas noch nie gemacht!

    muss ich da mit fseek in eine Zeile springen, prüfen ob das gewünschte Wort vorhanden ist und wenn nicht die Zeile mit fgets wegschmeißen?

    oder kann ich das Ganze einfacher gestalten?



  • Kennung der Zeilen IST nicht die Zeilenzahl sondern ein Wort.

    sorry



  • Da würde ich durchaus auch zeilenweise vorgehen und das Wort suchen. Das hier funktioniert, wenn das Suchwort am Anfang vorkommt.

    const string searchedWord = "Gurkensalat";
    string token;
    while(stream >> token && token != searchedWord)
        stream >> skip_line; // skip_line s.o.
    
    if(!stream)
        throw InvalidFileFormat();
    


  • PDD31 schrieb:

    Ich hab jetzt am Ende der Datei noch ziemlich viel Müll, zwischendrin eine Zeile die ich brauche und ganz am Ende nochmal eine wichtige Zeile.

    Bei Deinem Kenntnisstand ist es vermutlich das Beste, Du bleibst bei der Vorgehensweise aus Deinem ersten Posting.
    D.h., Du liest jede Zeile der Datei in einen String ein. Den String kannst Du mit Hilfe der Methoden der String-Klasse untersuchen - zB ob ein bestimmtes Wort drin vorkommt -, außerdem kannst Du ja auch die Zeilen mitzählen, für den Fall zB., dass Dich die ersten x Zeilen auf keinen Fall interessieren.
    Zeilen, die für Dich wichtig sind, weil sie zum Beispiel die drölfundzwanzigste Zeile sind, oder weil ein bestimmtes Wort drin vorkommt, verarbeitest Du wie gewünscht, die anderen ignorierst Du einfach.



  • @Eisflamme

    Danke 😃 und was funktioniert, wenn das Wort nicht am Anfang vorkommt?



  • Nun ja, es gibt da eine Variante mit unget. Aber die ist nicht sicher, weil unget anscheinend nicht sehr sicher ist.

    Und dann könnte man sich noch eine Variante denken, bei der man eine Wortsuche einbaut, die aber berücksichtigen müsste, dass ein Teil des Wortes bereits als neues potenzielles Wort dienen könnte. Das wird aber unübersichtlich und dann sollte man das vermutlich auch performant machen, wo ich mich dann aber einlesen müsste.

    Hm, ich frage mich gerade, wieso unget() nicht gesichert ist, wenn der filestream auch seekg anbietet. Oder sind das zwei verschiedene Schienen, die man kombinieren könnte, um eine sichere stringInLine-Suche ohne Extracten zu garantieren?

    Egal. Einfach und sicher ist:

    const string searchedWord = "Apfelkompott";
    string currentLine;
    while(getline(stream, currentLine) && currentLine.find(searchedWord) == string::npos);
    
    if(!stream)
        throw InvalidFileFormat();
    
    // currentLine ist jetzt die Zeile mit dem aktuellen Suchwort
    


  • Eisflamme schrieb:

    Einfach und sicher ist:

    const string searchedWord = "Apfelkompott";
    string currentLine;
    while(getline(stream, currentLine) && currentLine.find(searchedWord) == string::npos);
    
    if(!stream)
        throw InvalidFileFormat();
    
    // currentLine ist jetzt die Zeile mit dem aktuellen Suchwort
    

    Besser ist

    const string searchedWord = "Apfelkompott";
    string currentLine;
    size_t pos;
    
    while(getline(stream, currentLine) && (pos = currentLine.find(searchedWord)) == string::npos);
    
    if(pos == string::npos)
        throw InvalidFileFormat();
    

    So hast du auch gleich die Position und musst nicht den Stream nochmal konvertieren.



  • Er hat ja nicht gesagt, ob die Position des Schlüsselworts in der Zeile überhaupt relevant ist. 🙂 Wo müsste man den Stream konvertieren?



  • Eisflamme schrieb:

    Er hat ja nicht gesagt, ob die Position des Schlüsselworts in der Zeile überhaupt relevant ist. 🙂 Wo müsste man den Stream konvertieren?

    Zeile 5.
    Und ja, du hast Recht, vielleicht braucht er die gar nicht...



  • Achso, zu bool konvertieren oder wie?

    Jetzt hab ich wieder angefangen zu überlegen: Wenn nur der Text nach dem Wort wichtig ist, kann man sich getline sparen. Ist aber deswegen albern, weil ja bei der Suche nach Socke z.B. "SSSSocke" wieder ungets erfordert. Ich hätte wirklich gerne im Standard definiert, wie häufig unget klappen muss, so fallen streng genommen viele Möglichkeiten weg. 😞


Anmelden zum Antworten