Problem mit Vektoren und Auslesen einer Textdatei



  • Ich habe mir grade eine Funktion geschrieben, um mir Datei aus einer Textdatei auszulesen. Diese sieht so aus:

    \tx  \ty
    1\t432\t234
    2\t424\t798
    

    Das '\t' soll einen Tab-darstellen.

    Ich lese die File so aus:

    ifstream xyCoordinatesIfS;
    	xyCoordinatesIfS.open(path,ios::in);
    	vector <string> lineT (100);
    	int i = 1;
    	while ( getline(xyCoordinatesIfS,lineT[i], '\t')) {
    		if (i > 3 && i % 2 == 0 ) {
    			cout << lineT[i] << "\t" << i << endl;   //Die hier ist gemeint
    		}
    		i++;
    	}
    	xyCoordinatesIfS.close();
    	lineT.shrink_to_fit();
    	int test = lineT.size();
    	cout << test << endl;
    

    Bie der Anzeige in der Konsole bekomme ich immer nur den x-Wert, obwole eig. auch der y-Wert, getrennt von einem \n enthalten sein müsse. Dies weiss ich, weil wenn man das modulo entfernt, kann man dies sehen.
    Die Ausgabe mit modulo lautet bei der obigen bsp. Datei:

    432    4
    424    6
    

    ohne Modulo:

    432    4
    234
    2      5
    424    6
    798
    

    Kann es nun sein, das das 234 und 798 aus der Wert 6,5 oder so liegt? 😮 (ich weiss gibt es nicht, aber ich hoffe ihr wisst, was mich meine)

    So meine zweite Frage ist , wie man den Vektor auf seine besetzten Elemente verkleinen kann. Also bei der obigen Datei 6 anstatt der 100, die ich bei der Initialisierung angegeben habe, denn ohne geht es nicht.

    IDE ist MS VC++ Express auf Win7

    Ich hoffe ihr könnt mir weiterhelfen.



  • Problem gelöst!!!



  • Hallo Crysis_02,

    ich schließe aus der von Dir beschriebenen Ausgabe, dass die Datei so aussieht:

    x	y
    	432	234
    	424	798
    

    also ohne die Nummerierung am Anfang der Zeile.
    Wobei als Trennzeichen der Tabulator benutzt wird, was aber für das Einlesen irrelevant ist.
    Ich unterstelle weiter, dass Du an den Zahlen (Koordinaten) interessiert bist, und diese nicht als Strings brauchst. Dann wäre das eine brauchbare Lösung:

    #include <iostream>
    #include <fstream>
    #include <limits> // numeric_limits
    #include <vector>
    
    struct XY // diese Struktur nimmt eine Koordinate auf
    {
        int x_, y_;
    };
    
    int main()
    {
        using namespace std;
        vector< XY > coordinates; // leeren(!) Container anlegen
        const char* path="input.txt";
        ifstream xyCoordinatesIfS( path ); // ios::in ist überflüssig, wg. (I)fstream
        if( !xyCoordinatesIfS.is_open() )
        {
            cerr << "Fehler beim Oeffnen von " << path << endl;
            return -2;
        }
        xyCoordinatesIfS.ignore( numeric_limits< streamsize >::max(), '\n' ); // erste Zeile überlesen
        for( XY c; xyCoordinatesIfS >> c.x_ >> c.y_; ) // Koordinaten als ZAHLEN lesen
            coordinates.push_back( c ); // push_back fügt ein Element hinzu
        if( xyCoordinatesIfS.eof() ) // bis EOF, dann ok
        {
            cout << "Ok; " << coordinates.size() << " Koordinaten gelesen" << endl;
        }
        else
            cerr << "Lesefehler" << endl;
        return 0;
    }
    

    Du brauchst den Vektor auch nicht verkleinern - schon gar nicht mit shrink_to_fit() - das macht was anderes. std::vector ist eine dynamische Datenstruktur, die z.B. mit push_back sukzessive vergrößert wird. Die Methode size() gibt Dir dann die Anzahl der im vector enthaltenen Elemente zurück.

    Um das Einlesen etwas eleganter zu gestalten, kannst Du noch für die struct XY einen Streamingoperator hinzufügen:

    std::istream& operator>>( std::istream& in, XY& c )
    {
        return in >> c.x_ >> c.y_;
    }
    

    dann vereinfacht sich Zeile 23 zu

    for( XY c; xyCoordinatesIfS >> c; )
    

    Gruß
    Werner



  • Nee. Die Datei hat vorne noch die Zahlen.

    X	Y
    1	287	454
    2	587	789
    

    zur Zeit habe ich es so gelöst.

    vector <int> solarCoordinateTransformation::GetXYCoordinates(string path) {
    	ifstream xyCoordinatesIfS;
    	xyCoordinatesIfS.open(path,ios::in);
    	vector <string> lineV (10);
    	int b = 0;
    	if (xyCoordinatesIfS.is_open())
    	{
    		//Hier mit den Limits?
    		while(!xyCoordinatesIfS.eof()) {
    			lineV.resize(b+1);
    			xyCoordinatesIfS >> lineV[b];
    			b++;
    		}
    	}
    	xyCoordinatesIfS.close();
    	int test = lineV.size();
    	int VectorSize = lineV.size()-3;
    	int VectorS = VectorSize/3*2;
    	vector <string> line (VectorS);
    	int e = 0;
    	int f = 1;
    	for (int d = 0; d < lineV.size() -1; d++) {
    		if (d > 2) {
    			if (f != 3) {
    				line[e] = lineV[d];
    				e++;
    				f++;
    			} else {
    				f = 1;
    			}
    		}
    	}
    	vector <int> returnValue (line.size());
    	for (int h = 0; h < line.size(); h++) {
    		returnValue[h] = atoi(line[h].c_str());
    	}
    	return returnValue;
    }
    

    Jedoch finde ich das mit den "limits" sehr cool. Wo muss ich dies jedoch in meinem code hinschreiben? Hab mal oben nen Kommentar reingemacht, wo ich denke, wo es hinkommt 😃

    Ich weiss es sieht nicht so gut aus, aber er funktioniert bei einer gewissen Ordnerstrunktur, die ich überall habe. Das Programm ist ja nur für mich ^^



  • Hallo Crysis_02,

    Crysis_02 schrieb:

    Nee. Die Datei hat vorne noch die Zahlen.

    X	Y
    1	287	454
    2	587	789
    

    Dann erweitere die Zeile 23 in meinem ersten Posting zu:

    int nr;
        for( XY c; xyCoordinatesIfS >> nr >> c.x_ >> c.y_; ) // Koordinaten als ZAHLEN lesen
    

    Crysis_02 schrieb:

    zur Zeit habe ich es so gelöst. ...

    Jedoch finde ich das mit den "limits" sehr cool. Wo muss ich dies jedoch in meinem code hinschreiben? Hab mal oben nen Kommentar reingemacht, wo ich denke, wo es hinkommt 😃

    ja genau da, Du musst natürlich den Code dahinter entsprechend anpassen. Suche hier im Forum mal nach skipline.

    Crysis_02 schrieb:

    Ich weiss es sieht nicht so gut aus, aber er funktioniert bei einer gewissen Ordnerstrunktur, die ich überall habe. Das Programm ist ja nur für mich ^^

    Nein, es funktioniert nicht. Und zwar genau dann nicht, wenn hinter der letzten Zahl kein Zeilenende, sondern bereits ein EOF steht. Probier's aus.

    Ursache dafür ist zum einen der sehr verbreitete Fehler auf EOF statt auf Fail abzufragen und zum anderen die wahrlich kryptische Methode, wie Du die Strings weiter verarbeitest. Du benötigst drei Container für das Einlesen - nötig wäre maximal einer.
    Ganz einfache Regel: lese das was Du brauchst - nur das und mit dem richtigen Typ (was sonst).

    vector <int> solarCoordinateTransformation::GetXYCoordinates(string path) {
        ifstream xyCoordinatesIfS;
        xyCoordinatesIfS.open(path,ios::in); // ios::in ist überflüssig, das ist bereits ein i(nput)fstream
        vector <string> lineV (10); // diese Vorbelegung ist überflüssig und fehlerträchtig
        int b = 0;
        if (xyCoordinatesIfS.is_open())
        {
            //Hier mit den Limits?
            while(!xyCoordinatesIfS.eof()) { // NACH(!) dem Lesen immer auf !fail() abfragen -> endlos-Loop bei Lesefehler und undefiniertes Ende
                lineV.resize(b+1); // Oje - Performance-loch
                xyCoordinatesIfS >> lineV[b]; // Du brauchst Zahlen, warum dann Texte lesen?
                b++;
            }
        }
        xyCoordinatesIfS.close(); // überflüssig
        int test = lineV.size();
        int VectorSize = lineV.size()-3;
        int VectorS = VectorSize/3*2; // wenn hier jetzt der letzte String fehlt (s.o.), ist 'VectorS' um 1 zu klein -> Programmfehler
    
        // der Code der hier kommt, wäre überflüssig, wenn Du gleich nur das liest, was benötigt wird
        // das würde auch das Code-Verständnis wesentlich erhöhen
        vector <string> line (VectorS);
        int e = 0;
        int f = 1;
        for (int d = 0; d < lineV.size() -1; d++) {
            if (d > 2) {
                if (f != 3) {
                    line[e] = lineV[d];
                    e++; // gewöhne Dir prefix statt postfix an.
                    f++;
                } else {
                    f = 1;
                }
            }
        }
        vector <int> returnValue (line.size());
        for (int h = 0; h < line.size(); h++) {
            returnValue[h] = atoi(line[h].c_str());
        }
        return returnValue;
    }
    

    Du fährst sicher mit mit einer Struktur XY besser, als die Koordinaten X und Y hinter einander in einen vector<int> zu schreiben.
    Und GetXYCoordinates macht als Methode keinen Sinn, da sie weder lesend noch schreibend auf irgendwelche Klassenmeber zugreift. Mache daraus besser eine Funktion.

    Crysis_02 schrieb:

    Das Programm ist ja nur für mich ^^

    Trotzdem sollte es korrekt sein und kürzere Programme lassen sich auch einfacher lesen - auch von einem selbst.

    Gruß
    Werner



  • Werner Salomon schrieb:

    Suche hier im Forum mal nach skipline.

    Es gibt so viele nette Helfer von dir, aber ich habe leider keinen Überblick.

    Gibt es irgendwo Werners IO-Suite, in der sie alle zentral aufgelistet sind?



  • Danke. der Code ist echt fürzer und besser zu verstehen ^^

    Jedoch gind das mit den limits nicht. Hab jetzt einfach 100 eingegeben. Reicht auf jeden Fall.

    Sieht jetzt so aus:

    vector <XY> solarCoordinateTransformation::GetXYCoordinates(string path) {
    	ifstream xyCoordinates;
    	vector <XY> coordinates;
    	int nr;
    	xyCoordinates.open(path);
    	if(xyCoordinates.is_open()) {
    		xyCoordinates.ignore(100 /*numeric_limits< streamsize >::max()*/, '\n' ); // erste Zeile überlesen
    		for( XY c; xyCoordinates >> nr >> c.x >> c.y; ) // Koordinaten als ZAHLEN lesen
    			coordinates.push_back( c ); // push_back fügt ein Element hinzu
    		//if( xyCoordinates.eof() ) // bis EOF, dann ok
    		//{
    		//	cout << "Ok; " << coordinates.size() << " Koordinaten gelesen" << endl;
    		//}
    		//else {
    		//	cerr << "Lesefehler" << endl;
    		//}
    	}
    	return coordinates;
    
    }
    


  • Crysis_02 schrieb:

    Jedoch ging das mit den limits nicht.

    Hallo Crysis_02,

    .. mögliche Ursachen: Du hast ein #include <limits> vergesen, oder Du arbeitest mit dem Visual Studio und hast oben ein #include <windows.h> oder #include <stdafx.h> stehen. Im letzteren Fall füge als erste Zeile in stdafx.h oder in Deinem Sourcefile vor windows.h , falls Du kein stdafx.h benutzt, ein #define NOMINMAX ein.

    Gruß
    Werner



  • Ja benutze die windows.h

    Werde es morge probieren. Danke.



  • super jetzt geht alles 🙂 👍


Anmelden zum Antworten