string-variablen aus Textdatei lesen und in integer-Feld schreiben
-
Hallo,
ich habe folgendes Problem:
Ich möchte aus einer Textdatei Werte auslesen und in ein Array vom Typ integer überführen. Dabei ändert sich die Anzahl der Variablen mit der ebenfalls dort eingegebenen Variable Anz_Var. Die Datei sieht ungefähr so aus:**Anzahl Variablen: 3
Var_nr;uGrenze;oGrenze
1;5;50
2;44;450
3;50;100**Ich habe schon mit ifstream die Zeilen einlesen können. Komme aber dann nicht weiter.
Wie komme ich an die "3" und wandele den String dann in einen Integerwert? Diesen Wert weise ich dann einer Variable Anz_Var zu.
Dann ein 3D-Feld int array[Anz_Var] erstellen.
Wie kann ich das Feld mit den Werten füllen? (Die Zahlen 1, 5, 50 der ersten zeile und der anderen Zeilen sind immer durch ein Semikolon (bzw. einen Tab-Stopp) getrennt.)Vielen Dank für eure Mühe.
Grüße
Guddy
-
Hallo Guddy,
anbei mein Vorschlag:
#include <iostream> #include <fstream> #include <vector> #include <limits> template< char C > std::istream& Char( std::istream& in ) { char c; if( in >> c && c != C ) in.setstate( std::ios_base::failbit ); return in; } struct Foo { int m_var, m_uGrenze, m_oGrenze; }; std::istream& operator>>( std::istream& in, Foo& x ) { return in >> x.m_var >> Char<';'> >> x.m_uGrenze >> Char<';'> >> x.m_oGrenze; } std::istream& read3DArray( std::istream& in, std::vector< Foo >& dreiD_ ) { in.ignore( std::numeric_limits< std::streamsize >::max(), ':' ); std::size_t anzahl; char dummy; // das Lesen des 'dummy' garantiert, das sich der Lesezeiger in der Kommenatrzeile befindet if( (in >> anzahl >> dummy) .ignore( std::numeric_limits< std::streamsize >::max(), '\n' ) ) // Kommentar überlesen { std::vector< Foo > dreiD; dreiD.reserve( anzahl ); // optional for( Foo x; anzahl && in >> x; --anzahl ) dreiD.push_back( x ); if( in ) swap( dreiD, dreiD_ ); // ok; dann übernehmen } return in; } int main() { using namespace std; vector< Foo > dreiD; ifstream file( "C:/tmp/input.txt" ); if( !file.is_open() ) { cerr << "Fehler beim Oeffnen" << endl; return -1; } if( read3DArray( file, dreiD ) ) { cout << "alles klar!" << endl; } };(getestet und funktioniert)
frag' nach, wenn Du was nicht verstehst.
Gruß
Werner
-
Hallo Werner,
viel verstehe ich leider nicht.
hier erzeugst du eine Funktionsvorlage, aber warum?
template< char C > std::istream& Char( std::istream& in ) { char c; if( in >> c && c != C ) in.setstate( std::ios_base::failbit ); return in; }Ist struct eine Ansammlung von Werten verschiedener Datentypen, in dem Fall halt mal gleich? Wozu brauch ich das?
struct Foo { int m_var, m_uGrenze, m_oGrenze; };Was passiert hier? Liest das Programm das Objekt x ein? Was bedeutet das &?:
std::istream& operator>>( std::istream& in, Foo& x ) { return in >> x.m_var >> Char<';'> >> x.m_uGrenze >> Char<';'> >> x.m_oGrenze; }Den folgenden Abschnitt versteh ich leider auch nicht...Kannst du das noch etwas beschreiben?
std::istream& read3DArray( std::istream& in, std::vector< Foo >& dreiD_ ) { in.ignore( std::numeric_limits< std::streamsize >::max(), ':' ); std::size_t anzahl; char dummy; // das Lesen des 'dummy' garantiert, das sich der Lesezeiger in der Kommenatrzeile befindet if( (in >> anzahl >> dummy) .ignore( std::numeric_limits< std::streamsize >::max(), '\n' ) ) // Kommentar überlesen { std::vector< Foo > dreiD; dreiD.reserve( anzahl ); // optional for( Foo x; anzahl && in >> x; --anzahl ) dreiD.push_back( x ); if( in ) swap( dreiD, dreiD_ ); // ok; dann übernehmen } return in; }Danke für deine Mühe, ich hab leider bis jetzt nur mit statischen Feldern gearbeitet...
Grüße
Guddy
-
Wiedermal wunderschön Werner. Ist man bei dir ja auch inzwischen nicht anders gewöhnt, wenns vorallem um Streams geht

Insbesondere die Idee mit dem Char<';'> gefällt mir außerordentlich gut

[Code in Lesezeichen save]
-
Wozu ist das "Char<';'>" gut? Danke.
-
Hallo,
hab mir das ganze nochmal reingezogen und einiges verstanden, denk ich. Ich hab mal Kommentare in den Quelltext geschrieben. Vielleicht könnt ihr mir Feedback geben ob ich das richtig vestehe oder nicht.
t
emplate< char C > std::istream& Char( std::istream& in ) { char c; if( in >> c && c != C ) in.setstate( std::ios_base::failbit ); return in; } struct Foo { int m_var, m_uGrenze, m_oGrenze; }; std::istream& operator>>( std::istream& in, Foo& x ) //formatierter input (was bedeuten die Werte in den Klammern? in=Name des iputstream?? und Ausgabe in x?? { return in >> x.m_var >> Char<';'> >> x.m_uGrenze >> Char<';'> >> x.m_oGrenze; //gibt Werte des inputstream in zurück aber ohne ";"? und zwar in die Variablen der Strucktur x? } std::istream& read3DArray( std::istream& in, std::vector< Foo >& dreiD_ ) //Definier von istream abgeleitete Funktion read3DArray mit inputstreamquelle in und Ziel vector dreiD_ mit daten-bzw. structurtyp Foo { in.ignore( std::numeric_limits< std::streamsize >::max(), ':' ); // ignore(streamlänge, Zeichen) ignoriert Strom bis zu dem Punkt, wenn Streamlänge erreicht oder Zeichen gefunden std::size_t anzahl; //size_t übergibt Wert oder stringlänge von Anz_Var an Variable anzahl??? char dummy; // das Lesen des 'dummy' garantiert, das sich der Lesezeiger in der Kommenatrzeile befindet if( (in >> anzahl >> dummy) .ignore( std::numeric_limits< std::streamsize >::max(), '\n' ) ) // Kommentar überlesen { std::vector< Foo > dreiD; //erzeugt Vektor mit datentyp/Structur Foo mit namen dreiD? dreiD.reserve( anzahl ); // optional, reserviert ein Minimum an Speicher von anzahl für den Vector dreiD for( Foo x; anzahl && in >> x; --anzahl ) //Führe aus (Structur x; ?????; Zähle anzahl runter dreiD.push_back( x );//fülle Vektor dreiD mit x vom Structurtyp foo if( in ) // wenn in != o dann swap( dreiD, dreiD_ ); // ok; dann übernehmen, swap tauscht Werte von Object dreiD zu dreiD_ , Warum????? } return in; gib in zurück, warum??? } int main() { using namespace std; vector< Foo > dreiD; ifstream file( "/smb_mnt/tgutjahr/p/groupdrives/oe624-lsk/Aktuell/dipl/08-gutjahr/programme/Optimierungsprogramm/Testprogramme/test.txt" ); if( !file.is_open() ) { cerr << "Fehler beim Oeffnen" << endl; return -1; } if( read3DArray( file, dreiD ) ) { cout << "alles klar!" << endl; } };Was bedeutet das "&" in Zeilen wie dieser?
std::istream& Char( std::istream& in )Ist das eine Referenz? Welchen Sinn hat das?
Viele Grüße
Torsten
-
warum nimmst du keine cpp-tags? das wär vll für c++-quelltext gar ne so doof ^^
ja, ist ne referenz...
std::istream& Char( std::istream& in )hier wird immer nur eine Referenz kopiert... (ist so was wie ein Pointer)
std::istream Char( std::istream in )So geht es zwar auch, aber jedes mal wird der istream (unnötig) kopiert...
bb
-
Streams können nicht kopiert werden

-
stanmc schrieb:
Wozu ist das "Char<';'>" gut? Danke.
Das dient ausschließlich dazu, ein Semikolon einzulesen und - falls da kein Semikolon kommt - den Stream in den Fehlerstatus zu setzen.
Also wenn man z.B.: schreibtint i1, i2; if( cin >> i1 >> Char<';'> >> i2 ) { // i1 und i2 wurden gelesen // und es stand mit Sicherheit ein Semikolon dazwischendann kann man im Gutfall sicher sein, dass das Format im Stream so ist, wie es spezifiziert wurde.
Siehe dazu auch hier mit 'trenner' oder hier mit 'sep'.
Gruß
Werner
-
guddy schrieb:
hab mir das ganze nochmal reingezogen und einiges verstanden, denk ich. Ich hab mal Kommentare in den Quelltext geschrieben. Vielleicht könnt ihr mir Feedback geben ob ich das richtig vestehe oder nicht. ...
Hallo Torsten,
aus Deinen Fragen schließe ich, dass ich bei Dir ziemlich weit vorn anfangen muss. Ich werde das hier nur kurz beantworten. Vielleicht schlägst Du die Themen nochmal zusätzlich in der Dir verfügbaren Literatur nach.
guddy schrieb:
struct Foo { int m_var, m_uGrenze, m_oGrenze; }; std::istream& operator>>( std::istream& in, Foo& x ) //formatierter input (was bedeuten die Werte in den Klammern? in=Name des iputstream?? und Ausgabe in x?? { return in >> x.m_var >> Char<';'> >> x.m_uGrenze >> Char<';'> >> x.m_oGrenze; //gibt Werte des inputstream in zurück aber ohne ";"? und zwar in die Variablen der Strucktur x? }In C++ ist ein Ausdruck wie
a = b + c;eine Funktion. Das ist ein Funktion mit zwei Parametern, was man auch so schreiben könnte:
a = operator+( int a, int b );D.h. die Funktion heißt 'operator+' und hat die beiden Parameter 'a' und 'b' und das Ergebnis - also den Returnwert der Funktion - weise ich hier 'c' zu.
Das kann man für fast alle Operatoren machen. Z.B. für den operator>>. Also statt zu schreiben
std::istream& lese_Foo_ein( std::istream& in, Foo& x )schreibt man
std::istream& operator>>( std::istream& in, Foo& x ). Das Ziel ist es nachher beim Aufruf einfach
Foo x; cin >> x;zu schreiben. Genauso wie man a+b und nicht addiere( a, b ) schreiben möchte.
Durch die Rückgabe der Referenz auf den Stream - und das muss(!) der selbe Stream sein wie der der übergeben wurde - erreicht man, dass man die Eingaben hintereinander schreiben kann. Etwa so
Foo x, y, z; cin >> x >> y >> z;guddy schrieb:
std::istream& read3DArray( std::istream& in, std::vector< Foo >& dreiD_ ) //Definier von istream abgeleitete Funktion read3DArray mit inputstreamquelle in und Ziel vector dreiD_ mit daten-bzw. structurtyp Foo { in.ignore( std::numeric_limits< std::streamsize >::max(), ':' ); // ignore(streamlänge, Zeichen) ignoriert Strom bis zu dem Punkt, wenn Streamlänge erreicht oder Zeichen gefunden std::size_t anzahl; //size_t übergibt Wert oder stringlänge von Anz_Var an Variable anzahl??? char dummy; // das Lesen des 'dummy' garantiert, das sich der Lesezeiger in der Kommenatrzeile befindet if( (in >> anzahl >> dummy) .ignore( std::numeric_limits< std::streamsize >::max(), '\n' ) ) // Kommentar überlesen { std::vector< Foo > dreiD; //erzeugt Vektor mit datentyp/Structur Foo mit namen dreiD? dreiD.reserve( anzahl ); // optional, reserviert ein Minimum an Speicher von anzahl für den Vector dreiD for( Foo x; anzahl && in >> x; --anzahl ) //Führe aus (Structur x; ?????; Zähle anzahl runter dreiD.push_back( x );//fülle Vektor dreiD mit x vom Structurtyp foo if( in ) // wenn in != o dann swap( dreiD, dreiD_ ); // ok; dann übernehmen, swap tauscht Werte von Object dreiD zu dreiD_ , Warum????? } return in; gib in zurück, warum??? }Eine Funktion kann man nicht ableiten. Das gilt nur für Klassen bzw. Strukturen. readArray ist einfach eine Funktion mit zwei Parametern. Beide Parameter werden als - nicht const - Referenz übergeben; d.h. man kann die Werte ändern, die außerhalb der Funktion deklariert werden.
Die Funktion von ignore hast Du richtig verstanden -es wird bis zum Doppelpunkt inklusive alles überlesen.
size_t ist ein Typ wie int. Ich hätte auch 'int anzahl;' schreiben können. Nur der Standard gibt vor die Anzahl der Elemente in einem Container als std::size_t zu deklarieren. Denke einfach es wäre ein int, dann passt das.
dreiD und reserve passt.
Du kennst sicher for-Schleifen in der Art
for( int i = 0; i < 5; ++i )Genauso wie dort ein int namens 'i' angelegt wird, habe ich bei mir ein Foo namens 'x' angelegt - ist genau das selbe.
Im mittleren Teil steht eine Bedingung, also ein Ausdruck der in ein bool konvertiert werden kann. Einmal ist es 'i < 5' d.h. die Schleife wird solange durchlaufen solange i kleiner als 5 ist - in meinem Fall ist es eine UND-Bedingung d.h. beide Ausdrücke rechts und links von '&&' müssen 'true' sein, damit die Schleife durchlaufen wird.
Links steht 'anzahl' - das ist true solange anzahl ungleich 0 ist. Und rechts steht in >> x. Das ist das Einlesen eines Foo-Objekts namens 'x' vom Input 'in'. Wie schon oben beschrieben gibt das eine std::istream& zurück. Diese Referenz ist in bool konvertierbar und liefert ein 'true' zurück, solange der Stream keinen Lesefehler hat.
Wichtig ist noch - der zweite also rechte Ausdruck eines '&&' wird nur genau dann ausgeführt, wenn der erste bereits 'true' ist. D.h. wenn die 'anzahl' bei 0 ankommt, wird auch kein x mehr vom stream gelesen. Das ist wichtig, weil im Stream keines mehr kommt und man vielleicht danach noch etwas anderes aus dem Stream lesen möchte.Das swap hat den Zweck die gelesenen Daten in 'dreiD' nach 'dreiD_' zu schaufeln, denn das ist ja der Parameter, der per Referenz übergeben wurde und der soll ja geändert bzw. gefüllt werden.
Gruß
Werner
-
KasF schrieb:
Insbesondere die Idee mit dem Char<';'> gefällt mir außerordentlich gut
Mir nicht. Damit kannst du nicht mal den Nutzer die Möglichkeit anbieten, dass der Separator optional gewählt werden kann, weil eine Änderung bei Templates nur mit neukompileren möglich ist. Eine einfache Funktion mit Parameter wäre da komfortabler und flexibler. Außerdem sollte man den gleichen Separator auch nicht X mal im Code verteilen, sondern als Konstante halten.
@guddy
Hier mal ein Lösungsansatz der deinem Niveau entspricht.int main() { std::ifstream file( "C:/tmp/input.txt" ); if( !file.is_open() ) { std::cerr << "Fehler beim Oeffnen" << std::endl; return -1; } file.ignore( std::numeric_limits< std::streamsize >::max(), ':' ); size_t arraySize; file >> arraySize; std::string comment; file >> comment; //geht hier so einfach, da Var_nr;uGrenze;oGrenze ein Wort ist int varNr, uGrenze; char separator; //Hier noch ein array erstellen und ne Schleife rum file >> varNr >> separator >> uGrenze; // usw... };Fehlerprüfung kannst/musst du auch noch einbauen und wenn du willst noch ein paar structs und Funktionen zur Übersichlichkeit.
-
Hallo,
ich hab mal "mal einfach"s Variante probiert, weil sie mir einfacher erscheint.
Ich hab deine Anweisungen befolgt, aber der compiler spuckt einige folgender Fehlermeldungen aus:C:29: error: no match for 'operator>>' in 'file.std::basic_ifstream<char, std::char_traits<char> >::<anonymous>.std::basic_istream<_CharT, _Traits>::operator>> [with _CharT = char, _Traits = std::char_traits<char>](((int&)(& varNr))) >> separator'Kann es sein, dass die datentypen nicht übereinstimmen? im stream stehen ja eigentlich string oder char. Ich habe aber oGrenze, usw. als int definiert. Wenn ich sie jedoch als char definiere kommen ähnliche fehler...
Wo leigt der Fehler?Der Quellcode:
#include <iostream> #include <fstream> int main() { std::ifstream file("Variableninput.dat"); if( !file.is_open() ) { std::cerr << "Fehler beim Oeffnen" << std::endl; return -1; } file.ignore( std::numeric_limits< std::streamsize >::max(), ':' ); size_t arrayHeigth; file >> arrayHeigth; std::string comment; file >> comment; //geht hier so einfach, da Var_nr;uGrenze;oGrenze ein Wort ist, ansonsten: file.ignore( std::numeric_limits< std::streamsize >::max(), '\n' ) ) int varNr, uGrenze, oGrenze, arrayWidth; const char* separator = ";"; //Hier noch ein array erstellen und ne Schleife rum int varArray[arrayHeigth] [arrayWidth]; arrayWidth = 3; for (unsigned int i = 1; i <= arrayHeigth; i++) { file >> varNr >> separator >> uGrenze >> separator >> oGrenze >> "\n"; varArray [i] [1] = varNr; varArray [i] [2] = uGrenze; varArray [i] [3] = oGrenze; std :: cout << varArray [i] [1] << "\t" << varArray [i] [2] << "\t" << varArray [i] [3]<< "\n"; } }
-
Hallo Leute,
ich hab mal Werners Code probiert und ihn auch einigermaßen verstanden. Ich möchte nun noch ein paar Änderungen vornehmen. Die Inputdatei sieht jetzt wie folgt aus:
Prozessname: Rankine Datum oder Zifferncodierung: 66 GA-Typ: 1 Genome-Typ: 2 Testfunktionstyp: 1 Anzahl der Durchläufe: 100 Anzahl der Variablen:3 Var_nr;uGrenze;oGrenze 1;5;50 2;44;450 3;55;500In der alten Datei wurden nur die Anzahl der Variablen eingelesen.
Wie kann ich Werners Code abändern um die Werte nach ":" als char (bei Prozessname, Datum oder Ziffern) und als int (bei GA-Typ, testfunktion und Anzahl der durchläufe) abzuspeichern?
Hier nochmal der Code:
#include <iostream> #include <fstream> #include <vector> #include <limits> template< char C > std::istream& Char( std::istream& in ) { char c; if( in >> c && c != C ) in.setstate( std::ios_base::failbit ); return in; } struct Foo { int m_var, m_uGrenze, m_oGrenze; }; std::istream& operator>>( std::istream& in, Foo& x ) //formatierter input (was bedeuten die Werte in den Klammern? in=Name des iputstream?? und Ausgabe in x?? { return in >> x.m_var >> Char<';'> >> x.m_uGrenze >> Char<';'> >> x.m_oGrenze; //gibt Werte des inputstream in zurück aber ohne ";"? und zwar in die Variablen der Strucktur x? } std::istream& read3DArray( std::istream& in, std::vector< Foo >& dreiD_ ) //Definier von istream abgeleitete Funktion read3DArray mit inputstreamquelle in und Ziel vector dreiD_ mit daten-bzw. structurtyp Foo { in.ignore( std::numeric_limits< std::streamsize >::max(), ':' ); // ignore(streamlänge, Zeichen) ignoriert Strom bis zu dem Punkt, wenn Streamlänge erreicht oder Zeichen gefunden std::size_t anzahl; //size_t übergibt Wert oder stringlänge von Anz_Var an Variable anzahl??? char dummy; // das Lesen des 'dummy' garantiert, das sich der Lesezeiger in der Kommenatrzeile befindet if( (in >> anzahl >> dummy) .ignore( std::numeric_limits< std::streamsize >::max(), '\n' ) ) // Kommentar überlesen { std::vector< Foo > dreiD; //erzeugt Vektor mit datentyp/Structur Foo mit namen dreiD? dreiD.reserve( anzahl ); // optional, reserviert ein Minimum an Speicher von anzahl für den Vector dreiD for( Foo x; anzahl && in >> x; --anzahl ) //Führe aus (Structur x; ?????; Zähle anzahl runter dreiD.push_back( x );//fülle Vektor dreiD mit x vom Structurtyp foo if( in ) // wenn in != o dann swap( dreiD, dreiD_ ); // ok; dann übernehmen, swap tauscht Werte von Object dreiD zu dreiD_ , Warum????? } return in; //gib in zurück, warum??? } int main() { using namespace std; vector< Foo > dreiD; char prozessname[256]; ifstream file( "Variableninput.dat" ); if( !file.is_open() ) { cerr << "Fehler beim Oeffnen der Datei Variableninput" << endl; return -1; } if( read3DArray( file, dreiD, prozessname) ) { cout << "Vector eingelesen" << endl; cout << dreiD[1].m_var << endl;; } }Danke für eure Hilfe.