Datenstruktur für .ini Files
-
Na in der Initialisierung des Iterators, so wie es DrGreen oben geschrieben hat.
std::map<std::string,std::map<std::string, std::string> >::iterator foo2 = foo1;
foo1 ist std::map<std::string,std::map<std::string, std::string> > foo1; (da meckert er auch nicht und die Map funktioniert auch)
-
SirLant schrieb:
Na in der Initialisierung des Iterators, so wie es DrGreen oben geschrieben hat.
std::map<std::string,std::map<std::string, std::string> >::iterator foo2 = foo1;
foo1 ist std::map<std::string,std::map<std::string, std::string> > foo1; (da meckert er auch nicht und die Map funktioniert auch)
foo1 ist aber kein iterator. Einen solchen musst du aber liefern, z. B. so:
std::map<std::string,std::map<std::string, std::string> >::iterator foo2 = foo1.begin();
mfg
v R
-
Danke, hätte wohl schon früher mal etwas mehr mit iteratoren arbeiten sollen, aber das werd ich jetzt mal nachholen
-
Nach etwas tüfteln hab ich jetzt folgendes um die Map auszugeben und es scheint richtig zu sein, aber geht das nicht auch einfacher, kommt mir etwas kompliziert vor
Typedefs werd ich natürlich benutzen, aber das war ja nur zu testzwecken
for (std::map<std::string,std::map<std::string,std::string> >::iterator foo2 = foo1.begin(); foo2 != foo1.end(); ++foo2) { cout << foo2->first << endl; for (std::map<std::string,std::string>::iterator foo3 = foo2->second.begin (); foo3 != foo2->second.end(); ++foo3) cout << "\t" << foo3->second << endl; cout << endl << endl; }
-
und was is daran so kopliziert ?
-
map<string, map<string, string> >::iterator iter;
usw...
Wie war das nochmal mit dem selbst nachdenken??
-
fsljkhdykvb schrieb:
map<string, map<string, string> >::iterator iter;
usw...
Wie war das nochmal mit dem selbst nachdenken??Das hat doch DrGreen bereits gesagt und wie du siehst hab ich ja alles bereits zum laufen bekommen.
DEvent ich wollte wissen ob es auch "einfacher" bzw. kürzer geht, oder ob das der normale Weg ist, so wie ich es jetzt habe.
-
SirLant schrieb:
fsljkhdykvb schrieb:
map<string, map<string, string> >::iterator iter;
usw...
Wie war das nochmal mit dem selbst nachdenken??Das hat doch DrGreen bereits gesagt und wie du siehst hab ich ja alles bereits zum laufen bekommen.
DEvent ich wollte wissen ob es auch "einfacher" bzw. kürzer geht, oder ob das der normale Weg ist, so wie ich es jetzt habe.
Wie du bereits angedeutet hast, geht man den langen Schreibsessions aus dem Weg,
indem man hier mit typedef's arbeitet.Kuerzer geht es ansonsten nicht.
mfg
v R
-
Nach dem stressigen Wochenende hab ich heut endlich mal die Zeit gefunden mir Gedanken über das Design zu machen, aber mir gefällt das irgendwie nicht, was sagt ihr dazu
class IniReader /*Nen besseren namen such ich noch, wer hat Vorschläge?*/ { IniReader (string filename = ""); // Speichert den Dateinamen in fname ~IniReader (); // Macht gar nix, da ja alles automatisch gelöscht wird // Copy- und Zuweisungsoperator werden implementiert open (string filename); // Macht das gleiche wie der CTor oben close (); // Entfernt den fname und leert die map read (); // Die Datei wird geöffnet und eingelesen const_map_iter getContent (); // Liefert nen Iter auf den Anfang // der map, sind die Daten noch //nicht eingelesen, werden sie bei //der ersten Anfrage eingelesen //Variablen string fname; bool read; };
Wie gesagt irgendwie gefällt mir die Art nicht, wobei es von außen ja ganz praktisch ist, ich geb den Dateinamen an und hol mir die Daten einfach über nen Methodenaufruf und gemäß der LazyEvaluation wird die Datei erst gelesen, wenn sie wirklich gebraucht wird.
-
Hat keiner daran etwas auszusetzen
-
Ich würds so machen:
typedef map<string,map<string,string> > IniData; IniData read_ini_file(string); void write_ini_file(string,IniData);
Ich sehe eigentlich nicht warum man das in eine Klasse stopfen soll, wenn es ein typedef auch tut.
-
Hi!
@SirLant:
Also ich habe es ein wenig sehr anders gemacht. Habe einige Methoden mehr, die einzelne Aufgaben übernehmen. Diese werden von einer Hauptroutine aufgerufen. Zudem kann man sich die Werte als String, int oder double zurückliefern lassen.Hier hast du eine Beschreibungen:
http://www.fh-wedel.de/~bek/c/uebss04/ueb07ia.html
In dem Link wird auf eine andere Übung verwiesen, allerdings gefällt mir persönlich der Parser oben der die Whitespaces nur am Anfang und Ende entfernen soll besser, als der der alle entfernen soll:
http://www.fh-wedel.de/~bek/c/uebss04/ueb07.htmlVielleicht gibt's dir ja ein paar Gedankenanstösse, allerdings ist die iniLibrary.h in C, wobei es kein Problem sein sollte daraus eine Klasse zu machen.
Code-Hacker
-
Stimmt eigentlich bräuchte man keine Klasse, aber mit der Klasse hab ich den Vorteil, dass sich keiner um das freigeben des Speichers kümmern muss.
Der Inhalt soll ja von der Ini-Klasse nicht ausgewertet werden, sondern nur eingelesen.
-
Hi!
Achso. Also nur auslesen, ermitteln wo Chapter/Section, Key und Value kommt und dann wegschreiben. Dachte du wolltest noch das Ini-File auf Korrektheit prüfen.
Du solltest du nen default-Konstruktor haben der deine bool-Variable initialisiert. Da diese sonst nicht initialisiert ist und man getContent aufrufen kann, welche die Variable ja wohl benutzt um zu prüfen ob die Datei bereits gelesen wurde oder nicht. (Kann ja passieren das man open vergisst, wenn man den Konstruktor nicht verwendet hat).
Code-Hacker
-
SirLant schrieb:
Stimmt eigentlich bräuchte man keine Klasse, aber mit der Klasse hab ich den Vorteil, dass sich keiner um das freigeben des Speichers kümmern muss.
Aber Hallo und eine map zerstört sich etwa nicht von selbst? Mach es nicht unötig kompilziert:
{ IniData data=read_ini_file("test.ini"); cout<<"Value="<<data["Section"]["Value"]<<endl; }
Ist völlig legal, sicher gegen Speicherlöcher und noch dabei noch exceptionsafe. Wer mehr will ist bei C++ fehl am Platz.
Und die implementierung ist auch noch recht einfach:
typedef map<string,map<string,string> >IniData; IniData read_ini_file(string file){ ifstream in(file.c_str()); if(!in) error; string line; IniData ret; map<string,string>*pos=0; while(getline(in,line)){ size_t space_pos=line.find(' ',0);//Hau Leerzeichen raus while(space_pos!=string::npos){ line.erase(line.begin()+space_pos); space_pos=line.find(' ',0); } if(line=="")//leere Zeile continue; if(line[0]=='#')//Commentar continue; else if(line[0]=='['&&line[line.size()-1]==']'){//Section line.erase(line.begin()); line.erase(line.end()-1); ret[line]=map<string,string>(); pos=&ret[line]; } else{//Wertzuweisung if(!pos) error;//In keiner Section size_t equ=line.find('=',0); if(equ==string::npos) error;//Kann man natürlich auch als (*pos)[line]="1"; sehen (*pos)[line.sub_str(0,equ)]=line.sub_str(equ+1,line.lenght()-(equ+1); } } }
Hab ich jetzt gerade aus dem Kopf geschrieben also Syntax sind möglich vom Prinzip her hat das bei mir schon hunderte Male geklappt. error muss natürlich durch eine Exception oder return Fehlerwert ersetzt werden. Wenn Tabs drin sein können müssen die natürlich auf dem gleichen Weg wie die Leerzeichen rausfliegen.
Und damit kannst du ini Dateien wie:
# Hier kommt die Main Section [Main ] val =Hallo [ttt] foo=noch_mehr_foo
lesen
Wenn du lieber op[], Ctor, CopyCtor, op=, Dtor und noch ein privates read_ini_file schreibst dann mach es ruhig. Besonders ekonomisch ist das nicht und Vorteile hat es auch keine.
PS: In deiner Klasse fehlen ne Menge const
-
War ja auch nur der grobe Designentwurf deswegen fehlt da noch mehr als nur das const.
So wie du es machst hast du natürlich ebenfalls keine Probleme mit der Speicherverwaltung dafür, aber wird die ganze map kopiert und das wollte ich vermeiden, weshalb ich eben ne Klasse erstellen wollte.
Aber danke für die Funktion so nimmst du mir auf jeden Fall nen großes Stück an Arbeit ab