Signore_Ercole Temat założony przez niniejszego użytkownika |
Wczytywanie stringow z pliku txt » 2016-11-27 22:22:09 Witam. Borykam się z pewnym problemem w moim programie. Program to słownik angielsko-polski, wczytuje on plik txt, i zapisuje dane w tablicy stringów. Przy pobieraniu nowych slow zapisuje je, ale tylko ostanie słowa czyli kiedy dodaje wiecej niz jedno słowo z angielskim bądź polskim tłumaczeniem zapisuje on tylko jedno. Drugi problem to jak powrócić do początkowego menu, aby od nowa liczył ilość linii w pliku txt. Program starałem się pisać obiektowo, wiem, że to bardziej profesjonalnie powinno wyglądać, ale taki mój poziom narazie. Prosze o pomoc. Podrzucam kod w 3 plikach plik head.h #include <iostream> using namespace std;
class Words { public: string english; string polish; int number; void read(); void add_English_Polish( int ); void add_Polish_English( int ); void show( int ); }; plik functions.cpp #include <iostream> #include "head.h" #include <fstream> #include <cstdlib> using namespace std;
void Words::read() { fstream file; file.open( "Words.txt", ios::in ); if( file.good() == false ) { cout << "Opening file failed!"; exit( 0 ); } else { cout << "The file was successfully opened." << endl; } }
void Words::show( int nr ) { cout << nr << ". " << english << " - " << polish << endl; }
void Words::add_English_Polish( int nr ) { cout << nr << ". " << "Put a word: English then Polish" << endl; cin >> english >> polish; }
void Words::add_Polish_English( int nr ) { cout << nr << ". " << "Put a word: Polish then English" << endl; cin >> polish >> english; } plik main.cpp #include <iostream> #include "head.h" #include <fstream> #include <cstdlib> using namespace std; Words * w; int line_number, n; string const Plik( "Words.txt" );
int main() { char space = ' '; line_number = 0; string line; fstream file; file.open( "Words.txt", ios::in ); while( getline( file, line ) ) ++line_number; file.close(); w = new Words[ 200 ]; file.open( "Words.txt" ); for( int i = 0; i < line_number; i++ ) { file >> w[ i ].english; file >> w[ i ].polish; } n = line_number; int c; cout << endl << "Ilosc slowek: " << line_number << endl; cout << endl << "Choose one of the following options:" << endl << endl; cout << "1-Add English word" << endl; cout << "2-Add Polish word" << endl; cout << "3-Check base of words" << endl; cin >> c; switch( c ) { case 1: { char ch; for( int i = line_number; i < 200; i++ ) { w[ i ].add_English_Polish( i ); cin >> ch; n = + line_number; n++; cout << "Add more? Y/N"; if( ch == 'n' || ch == 'N' ) break; else if( ch == 'y' || ch == 'Y' ) continue; ofstream file( Plik.c_str() ); for( int i = line_number; i < n; i++ ) { file << w[ i ].english; file << space; file << w[ i ].polish; } file.close(); } break; cout << endl;; case 2: { char ch; for( int i = line_number; i < 200; i++ ) { w[ i ].add_Polish_English( i ); cin >> ch; n = + line_number; n++; cout << "Add more? Y/N"; if( ch == 'n' || ch == 'N' ) break; else if( ch == 'y' || ch == 'Y' ) continue; } ofstream file( Plik.c_str() ); for( int i = line_number; i < n; i++ ) { file << w[ i ].polish; file << space; file << w[ i ].english; } file.close(); } break; case 3: { for( int i = 0; i < n; i++ ) { w[ i ].show( i ); } } break; } } return 0; } |
|
karambaHZP |
» 2016-11-27 22:58:59 Znasz klasy, metody i funkcje, a jedziesz na kodzie spagetti? Podziel to sensownie na moduły. Nadaj swoim klasom i zmiennym sensowne nazwy i sam zaczniesz widzieć problemy. Zmienne globalne - samo zło. Tutaj niepotrzebne. using namesapce std; w pliku nagłówkowym to zła praktyka. Pchanie logiki do switch a powinno być karalne. Istnieją funkcje. Są kontenery, które idealnie pasują do słownika. np. std::multimap. edit: jak możesz wstaw kilka linii pliku, z którego czytasz hasła do słownika. edit2: proste użycie std::multimap. #include <iostream> #include <fstream> #include <string> #include <map>
class Dictionary { public: using mmapDictionary = std::multimap < std::string, std::string >; private: mmapDictionary dictionary; void Load(); const bool IsEntryExist( const std::string & entry, const std::string & translation ) const; public: Dictionary(); void AppEntry( const std::string & entry, const std::string & translation ); const mmapDictionary & GetDictionary() const { return this->dictionary; } void Save() const; friend std::ostream & operator <<( std::ostream & out, const Dictionary & dictionary ); };
Dictionary::Dictionary() { Load(); }
void Dictionary::Load() { std::ifstream fin( "fileName.txt" ); if( fin ) { while( true ) { typename mmapDictionary::key_type keyEng; typename mmapDictionary::mapped_type mappedPl; fin >> keyEng >> mappedPl; if( !fin.eof() ) { this->dictionary.insert( decltype( this->dictionary )::value_type( keyEng, mappedPl ) ); } else { fin.clear(); fin.close(); break; } } } else { } }
const bool Dictionary::IsEntryExist( const std::string & entry, const std::string & translation ) const { auto range = this->dictionary.equal_range( entry ); if( range.first != this->dictionary.cend() ) { for( auto i = range.first; i != range.second; ++i ) { if( i->second == translation ) { std::cout << "haslo istnieje\n"; return true; } } } return false; }
void Dictionary::Save() const { std::ofstream fout( "fileName.txt", std::ios::trunc ); if( fout ) { for( auto const & item: this->dictionary ) { fout << item.first.data() << ' ' << item.second.data() << '\n'; } } else { } }
void Dictionary::AppEntry( const std::string & entry, const std::string & translation ) { if( !IsEntryExist( entry, translation ) ) { this->dictionary.insert( decltype( this->dictionary )::value_type( entry, translation ) ); } }
std::ostream & operator <<( std::ostream & out, const Dictionary & dictionary ) { for( auto const & item: dictionary.dictionary ) { out << item.first << ' ' << item.second << '\n'; } return out; }
int main() { Dictionary dict; dict.AppEntry( "good", "dobry" ); dict.AppEntry( "different", "inny" ); dict.AppEntry( "alone", "samotny" ); dict.Save(); Dictionary dict2; std::cout << dict2 << '\n'; }
|
|
j23 |
» 2016-11-28 11:21:42 @karambaHZP, rozwiązanie z multimapą, które podałeś, jest OK. Problem w tym, że jest jednokierunkowe. Tutaj (dwóch) multimap użyłbym to tworzenia relacji między słowami, a same słowa trzymałbym w oddzielnych kontenerach. np. vector<> czy list<>. |
|
michal11 |
» 2016-11-28 11:42:21 Można też skorzystać z bimapyew. |
|
Signore_Ercole Temat założony przez niniejszego użytkownika |
» 2016-11-28 12:12:21 @karambaHZP, ogolnie sposób rozwiązania podany przez Cb jest dla mnie niezrozumiały, bo to jeszcze nie mój poziom. Dopiero zacząłem się wdrażać w OOP i prawdopodobnie za wcześnie chciałem napisać jakiś program, gdzie widze ze nie znam podstaw. Dzięki za odpowiedzi, menu zrobię za pomocą funkcji, wieczorem postaram się podrzucić nowy kod. Próbowałem skompilować kod w C::B i pokazało 29 error, a w VS 2015 zero błędów, (ostatecznie przerzucam się na VS) Ogólnie dzięki za kod bo dla mnie jest mega ambitny na tą chwile i mam co analizować w najbliższym czasie, mam pare pytan. Dlaczego nie można używać using namespace std; w plikach header, oraz dlaczego praktycznie się tego nie stosuje tylko np: void AppEntry( const std::string & entry, const std::string & translation ) w takiej postaci? |
|
mateczek |
» 2016-11-28 15:03:48 Próbowałem skompilować kod w C::B i pokazało 29 error, a w VS 2015 zero błędów, (ostatecznie przerzucam się na VS)
|
Pewnie z powodu braku włączenia c++11 https://youtu.be/SNLZEhWZ1og?t=259 |
|
karambaHZP |
» 2016-11-28 15:18:56 Dlaczego nie można używać using namespace std; w plikach header, |
Ponieważ dodajesz przestrzeń nazw we wszystkich miejscach i tracisz kontrolę, gdzie i kiedy jest dodana. Poza tym nie praktykuje się takiego rozwiązania. Ograniczasz sobie w ten sposób zasób identyfikatorów zmiennych, funkcji itd. Istnieje ryzyko zastosowania tej samej nazwy i zajdzie niejednoznaczność. PS: dzięki @j23 i @michal11 za uwagi. |
|
Signore_Ercole Temat założony przez niniejszego użytkownika |
» 2016-11-28 18:44:30 @mateczek dzięki za link, teraz już wszystko się kompiluje. |
|
« 1 » |