String-Operationen



  • Hallo,

    ich brauche einmal Hilfe:

    ich wollte eine Art Vokabeltrainer programmieren. Da ich leider keine Ahnung habe, wie ich Datenbanken in VS2012 Express (Desktop) benutze, habe ich eine "txt-Datenbank" angelegt, also eine Textdatei, wo die Vokabeln so gespeichert werden:

    Deutsch|Englisch;Deutsch2|Englisch2;
    

    Beim Auslesen habe ich aber ein Problem: Ich bekomme die Datei völlig in einen String gespeichert, aber ich weiß nicht, wie ich anhand der Trennzeichen die Vokabeln erst in ein String-Array als Wertpaare speichern (also anhand ';' trennen), und dann ein zufällig ausgewähltes Wertepaar noch einmal am '|' trennen kann.

    Ich hatte mir erst eine while-Schleife mit substr überlegt, aber das ist weder elegant, noch funktioniert überhaupt der Vokabel-Anzahl-Zähler:

    void EditEn()
    {
    	std::fstream DataStream;
    	DataStream.open( "DataBaseEn.txt", std::ios_base::out | std::ios_base::app );
    
    		std::fstream vocCounterStream;
    		vocCounterStream.open( "VocCounterEn.txt", std::ios_base::out | std::ios_base::in | std::ios_base::app );
    		vocCounterStream << "";
    
    		std::string inNumber;
    		int iVocCounter = 0;
    		std::string iVocAusgabe;
    
    		while( vocCounterStream.good() )
    		{
    			char c = vocCounterStream.get();
    
    			inNumber.push_back(c);
    		}
    
    		vocCounterStream.close();
    
    		iVocCounter = atoi( inNumber.c_str() );
    
    	std::string gerVoc;
    	std::string enVoc;
    
    	std::cout << "Vokabel-Editor Englisch" << std::endl;
    	std::cout << "Wichtig: Benutzen Sie diese Zeichen nicht( \"|\" und \";\" )" << std::endl;
    	std::cout << "Danke!" << std::endl;
    
    LOOP:
    	std::cout << "Bitte geben Sie ein deutsches Wort ein:" << std::endl;
    	getline( std::cin, gerVoc );
    
    	if( gerVoc == "Close();" )
    	{
    		DataStream.close();
    		return;
    	}
    
    	std::cout << "Geben Sie bitte die englische Bedeutung ein:" << std::endl;
    	getline( std::cin, enVoc );
    
    	DataStream << gerVoc << "|" << enVoc << ";";
    	iVocCounter++;
    	vocCounterStream << iVocCounter;
    
    	goto LOOP;
    
    	DataStream.close();
    	return;
    }
    

    Kann mir jemand helfen?

    Entweder mit einer Lösung, warum vocCounterStream nichts in eine Datei schreibt, oder, besser,
    eine Art String::Split() Methode, wie es sie bei CLI gibt.

    Vielen Dank!

    Player894



  • Dieser Thread wurde von Moderator/in Martin Richter aus dem Forum MFC (Visual C++) in das Forum C++ (auch C++0x und C++11) verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • http://www.cplusplus.com/reference/cstring/strtok/

    BTW: du benutzt goto, um eine Loop zu realisieren. 😮


  • Mod

    strtok schrieb:

    http://www.cplusplus.com/reference/cstring/strtok/

    BTW: du benutzt goto, um eine Loop zu realisieren. 😮

    Er benutzt auch atoi um Zahlen zu lesen. Da ist es vielleicht keine so gute Idee, ihm auch noch C-Stringoperationen zur Arbeit mit C++-Strings zu empfehlen, oder?

    Der korrekte Ansatz wäre hier, direkt auf Streamebene alles richtig zu zerlegen, den Umweg über den String spart man sich so. Und wenn überhaupt, dann bearbeiten wir C++-Strings mit ihren eigenen Methoden.



  • Hallo Player894,

    Player894 schrieb:

    Beim Auslesen habe ich aber ein Problem: Ich bekomme die Datei völlig in einen String gespeichert, ...

    das ist ganz unnötig. Du kannst direkt aus der Datei die Vokabeln lesen.

    Müsste im Prinzip so gehen:

    using namespace std;
        vector< pair< string, string > > dictionary; // pair.first -> deutsch; pair.second -> englisch
    
        int inNumber;
        DataStream >> inNumber; // ich vermute, ganz am Anfang steht die Anzahl der Vokabeln
        int i = 0;
        //                                                      Format:        "*<LF|Space> <deutsch>  | *<LF|Space> <englisch>  ;"
        for( pair< string, string > pr; i < inNumber && getline( getline( DataStream >> ws, pr.first, '|' ) >> ws,   pr.second, ';' ); ++i )
            dictionary.push_back( pr );
        if( DataStream ) // alles ok?
        {
            cout << dictionary.size() << " Eintraege gelesen" << endl;
            // usw. 'dictionary' enthält jetzt alle Vokabeln
        }
    

    Gruß
    Werner



  • Werner und du denkst der TE versteht davon was wenn er schon mit GOTO rumwerkelt?


  • Mod

    CTecS schrieb:

    Werner und du denkst der TE versteht davon was wenn er schon mit GOTO rumwerkelt?

    Das ist vor allem eine Sache des TE, das er nie vernünftig C++ gelernt hat (wo bekommt man eigentlich GOTO beigebracht?). Werners Vorgehensweise ist die, wie man es richtigerweise machen würde. Meinetwegen mit mehr Zwischenschritten, aber die Hauptpunkte sind:
    1. Direkt aus dem Stream lesen, keine Umwege über Strings
    2. Standardbibliothek für sich arbeiten lassen
    2b. C++-Standardbibliothek für sich arbeiten lassen, nicht die C-Standardbibliothek auf C++-Objekte anwenden.
    3. Saubere Kontrollstrukturen, kein goto.

    Vernünftige Lehrbücher und Links für Anfänger findet der Threadersteller hoffentlich selbstständig im Forum.



  • ^^


  • Mod

    😮 Troll? Account gehackt? Meint der das ernst? 😕



  • Ich hab dir ja ne Mail geschrieben...
    😕
    ^^


  • Mod

    Player894 schrieb:

    was meine ich ernst

    Na, deinen vorletzten Beitrag. Das ist ziemlicher Unsinn, auf ganz niedrigem Niveau. Darauf antworte ich nicht einmal im Details, weil ich nicht glauben kann, dass das kein Trollversuch sein soll. Falls du das wirklich ernst meinen solltest, wirst du damit voll auf die Schnauze fliegen. Wahrscheinlich sogar bald.



  • Werner Salomon schrieb:

    Müsste im Prinzip so gehen:

    vector< pair< string, string > > dictionary; // pair.first -> deutsch; pair.second -> englisch
    

    Was soll das werden?
    "Im Prinzip" nimmt man für ein Wörterbuch map und nicht vector.

    Werner Salomon schrieb:

    // usw. 'dictionary' enthält jetzt alle Vokabeln
    

    Und, wie soll er den vector nun für sein Wörterbuch gebrauchen?
    Jedesmal iterieren?



  • "Im Prinzip" nimmt man für ein Wörterbuch map und nicht vector.

    Ja, aber nur im Prinzip. Denn eine map ist für ein Wörterbuch nicht viel geeigneter als ein vector .



  • Player894 schrieb:

    Was habt ihr alle gegen GOTO???

    Einfach: Es vermindert die Lesbarkeit und damit Wartbarkeit des Codes, zwei sehr essenzielle Faktoren beim Programmieren.

    C++ ist C.

    Nein, nein und nochmals nein. Das ist etwas, was SeppJ hier leider irgendwie jedem zweiten Uni-Lehrling erklären muss. C++ und C sind zwei verschiedene Sprachen mit gleicher Syntax. Wenn du versuchst, C mit einem C++-Compiler zu kompilieren, dann nimm gleich einen C-Compiler.

    oder meinetwegen einer Funktion wie .toint() oderso

    Die gibt es, std::stoi .

    Außerdem ist GOTO bewährter als alles andere aus C++, da ganz C++ nunmal in GOTO - "Krams" namens Maschninensprache übersetzt wird.

    Richtig. Laut deiner Argumentation sollten wir alle Assembler lernen und von Hochsprachen die Finger lassen. Dir fällt auf: Du bist inkonsistent.

    Und ob ich jetzt eine while-Schleife nehme und der Compiler dass dann in GOTO-Strukturen verwandelt, oder ob ich einfach gleich GOTO verwende ist letztlich egal.

    Erstens: Meintest du nicht, das ersteres langsamer ist?
    Zweitens: Nein, uns nicht. Ich weigere mich hiermit, solchen Code zu lesen. Mir fehlen die masochistischen Veranlagungen.



  • Hallo Wutz,

    Wutz schrieb:

    Werner Salomon schrieb:

    Müsste im Prinzip so gehen:

    vector< pair< string, string > > dictionary; // pair.first -> deutsch; pair.second -> englisch
    

    Was soll das werden?
    "Im Prinzip" nimmt man für ein Wörterbuch map und nicht vector.

    Und, wie soll er den vector nun für sein Wörterbuch gebrauchen?
    Jedesmal iterieren?

    das mit vector statt map war schon Absicht. Player894 hat uns seinen endgültigen Use Case ja nicht genau verraten (eine Art Vokabeltrainer s.o.). Wenn er es als Lernhilfe benutzt, bei der zufällig ausgewählte Worte übersetzt werden sollen, macht eine map gar keinen Sinn. Hier ist ein sequentieller Container mit random access Zugriff besser. Eventuell sollte man dann std::pair<> noch durch eine struct/class ersetzen, um weitere Informationen dort abzulegen. Aber das war nicht das Thema dieses Threads.
    Braucht er es als Wörterbuch zum Nachschauen, so kann er es nach den deutschen oder den englischen Begriffen sortieren. Je nach dem was gesucht wird. Dann ist ein std::lower_bound praktisch genauso performant wie das find einer map . Und selbst ein simpler std::find wäre für eine Anwendung, bei der jedes Wort vom Benutzer eingegeben werden muss, auch bei mehreren tausend Einträgen IMHO kein Problem.

    Gruß
    Werner



  • Nene, Player894 hat schon recht. Keiner ausser ihm hier hat Ahnung, immerhin ist es ja er hier, der die Anfängerfrage stellt 👍 🤡 💡


Anmelden zum Antworten