.txt Datei einlesen und in Vectoren speichern



  • while(!inAirport.eof)
    inAirporFile>> vector<string> ;
    
    //so oder so ähnlich probier etwas aus
    

    http://www.cplusplus.com/reference/fstream/ifstream/



  • Dieser Beitrag wurde gelöscht!


  • Habe ein wenig rumprobiert aber es scheint nichts so wirklich zu Funktionieren. Muss ich nacheinander bis zum nächsten Komma einlesen lassen und das Element welches bis dorthin eingelesen wurde zwischenspeichern in bsp einem String, und die einzelnen strings dann am ende der Zeile in einen Vector speichern?

    Wenn ja wie genau stell ich das an?



  • So kompliziert is das gar nicht, erstell eine klasse der du eine zeile übergibst. Diese zerlegt dann die Zeile anhand der Kommas. Die einzelnen Werte speicherst du dann in entsprechende Strings in deiner Klasse. Die Klasse speicherst du dann in einen Vector oder Liste oder was du auch immer für einen Container dafür benutzt um die ganzen Zeiger dir zu merken. Wenn das alles so weit funktioniert daust du dir eine "masterklasse die das ganze Kapselt, also deine einzelnen Aufrufe für dich erledigt und schon brauchst du nur die Datei an zu geben und der rest erledigt sich von selbst genau so wie etwas zu suchen weil du nur Funktionen der unteren Klassen auf rufst.
    Vereinfach jede aufgabe auf das kleinste geminsame vielfache hier eben die zeile dann erkennt man schnell den rest und vereinfacht so das konstrukt und die entwicklung des Programmes.



  • hab's eben nochmal probiert so ungefähr sollte es ausehen wenn ich verstanden habe was du wolltest

    #include<iostream>
    #include<fstream>
    #include<map>
    int main()
    {
        std::fstream r ("text.txt");
        std::map<int,std::string> e;
        std::string w;
    
            do{
                 int i=0;
                char help ;
                while(r.get(help))
                {
                    if(help==',')i++;
                    else e[i]+=help;
    
                }
    
    
              }while(!r.eof());
              r.close();
              for(int f =0; f<6;f++)std::cout<< e[f]<< std::endl;
    
        return 0;
    }
    //mit >> gehts auch 
    


  • @CTecS Aber mit dem Code " ifstream inAirportFile("airports.txt", ios::in); " übergebe ich doch das gesamte Textdokument oder nicht? Wie kann ich denn dann erreichen das der Compiler nur aus einer Zeile, ein Wert bis zu einem Komma nimmt und in dem entsprechenden String zwischenspeichert, dann den nächsten Wert im nächsten String usw. bis zum Ende der Zeile. Und das ganze so im Vector speichert, das es trotzdem "zusammenhängend" ist, sodass ich einen Wert angeben kann und mir das Programm die Informationen ausgibt.



  • Jetzt hast du die Strings von einem Flughafen in einer map.
    Du solltest dir aber überlegen, wie du etwas Sinnvolles damit anfangen könntest. Sinnvoll wäre z.B. das Sortieren nach Kennung/Stadt/Land oder, wenn die Liste sehr viele Flughafen umfasst, zu bestimmen, welche Flughäfen angeflogen werden müssen, wenn man mit der Spirit of St. Louis und möglichst wenig Zwischenstopps von Los Angeles über Paris nach Peking fliegen möchte.
    Selbst wenn du die maps in einen vector stecken würdest, wären die oben gestellten Aufgaben zumindest nur umständlich lösbar, oder?
    Halt dich an den Vorschlag von CTecS, erstelle dir eine Klasse Airport, die die Eigenschaften bereitstellt.

    class Airport
    {
      // was gehört hier alles rein?
    };
    

    Einlesen ginge dann auch durch Operatorüberladung: ifstream& operator >> (ifstream& in, Airport &ap). Als friend wie z.B. hier beschrieben.
    Es gibt da aber auch noch andere Wege, notfalls kann auch mit Settern gearbeitet werden.
    Mit einem std::vector<Airport> könnte man dann schon eine Vielzahl von Standardproblemen lösen.
    Mit den US-Staaten kommts drauf an, was genau zu machen ist. Wenn sich der Flughafen in den USA befindet, dann könnte die Abkürzung in den kompletten Namen umgewandelt werden („MS” -> Mississippi). Also einlesen, mit dem vector der Flughäfen vergleichen und ggf. ersetzen.



  • @yahendrik Eine Klasse Airport habe ich bereits angelegt die alles bereitstellen soll. Zurzeit habe ich da mehrere string Variablen und double Variablen angelegt. Insgesamt 8 stück, da eine Zeile des Dokuments 8 Elemente bereithält. Zudem einen Vector namens "Flughaefen" vom typ Airports und den Standartkonstruktor gefüllt mit den Variablen. Damit ich ein Objekt anlegen kann welches ich anschließend in den Vector laden kann, da ich dachte dass das eventuell die Lösung sein könnte



  • Die Daten sehen ja sehr nach CSV aus. Ich würde daher raten, eine CSV-Library zu benutzen, damit das Programm problemlos weiterläuft, wenn die Spalten durcheinandergewürfelt werden. Zum Beispiel https://github.com/ben-strasser/fast-cpp-csv-parser

    Deswegen denke ich auch, dass ein einfaches ifstream& operator >> (ifstream& in, Airport &ap) nicht ausreicht, weil der operator>> noch irgendwie wissen müsste, in welcher Reihenfolge die Spalten einzulesen sind.



  • @wob Naja, ich würde davon ausgehen, dass die Daten immer in der richtigen Reihenfolge vorhanden sind. Gerade bei Übungsaufgaben.
    Wenn es nicht so wäre, wäre es auch das völlig falsche Format. Dann könnte man bspw. Konfigurationsdateien mit Sections und Keys als Vorlage nehmen.



  • Das sind Übungsaufgaben für eine Klausur. Beziehungsweise ist das die Klausur welche 2018 geschrieben wurde. Und in der Klausur habe ich auch keinen Zugriff auf eine CSV Library



  • Nimm ne map und fertig ist der Lack.Die funktion könnt ihr etwas bearbeiten ist noch nicht perfekt z.b.map <string,string> willste nur die den ersten string bis komma einlesen nimmste die do schleife weg. und machstest bei if ein breake;.bzw return wenn die funktion ganz verlassen werden soll.



  • void Airport::AusDateiLesen()
    {
    	ifstream AirportDatei("airports.txt", ios::in);
    	string zeile;
    	while (getline(AirportDatei, zeile))
    	{
    		for (int i = 0; i < zeile.size(); i++)
    		{
    			if (zeile[i] == ',')
    			{
    				zeile[i] = ' ';
    			}
    		}
    		stringstream zeilenpuffer(zeile);
    		string iata;
    		string airport;
    		string city;
    		string stateAbbreviation;
    		string country;
    		double breite;
    		double laenge;
    		zeilenpuffer >> iata >> airport >> city >> stateAbbreviation >> country >> breite >> laenge;
    
    		Flughaefen.push_back;
    
    		cout << Flughaefen.size;
    	}
    }
    

    So sieht meine Funktion in Airport.cpp momentan aus. Funktioniert allerdings nicht so wirklich, bekomme fehler in Zeile 24 und 26...



  • die () fehlen



  • Bei Flughaefen.push_back akzeptiert er keine (), ich kann auch nichts übergeben. Mit Flughaefen.emplace_back(); kommt zumindest keine Fehlermeldung. Allerdings kommt bei der Ausgabe eine Zahlenfolge die mir definitiv falsch vorkommt..



  • Dieser Beitrag wurde gelöscht!


  • Der Ansatz ist schon ganz richtig, nur dürfen die Variablen iata, airport ... und so weiter die du in der Funktion AusDateiLesen() als lokale Varablen definiert hast, keine lokalen Variablen sein, denn sonst sind die ja mit verlassen der Funktion AusDateiLesen() wieder weg. Diese musst du in den Header der Klasse Airport übernehmen und auch nur diese dann "befüllen". Schlussendlich arbeitet das die Klasse Airport nur mit den paar Variablen.

    Beispiel weil es einfacher ist als das ganze zu erklären:

    class Airport
    {
        Airport(string zeile)
        {
            stringstream zeilenpuffer(zeile);
    		zeilenpuffer >> iata >> airport >> city >> stateAbbreviation >> country >> breite >> laenge;
        };
        
    protected:
    	string iata;
    	string airport;
    	string city;
    	string stateAbbreviation;
    	string country;
    	double breite;
    	double laenge;
    };
    class Flughaefen 
    {
        ReadCSV(string Path)
        {
            ifstream AirportDatei("airports.txt", ios::in);
            string zeile;
        	while (getline(AirportDatei, zeile))
        	{
        		for (int i = 0; i < zeile.size(); i++)
        		{
        			if (zeile[i] == ',')
        			{
        				zeile[i] = ' ';
        			}
        		}
                Airport AP(zeile);
                Airports.pushback(AP);
        	}
        };
    protected:
        vector<Airport> Airports;
    };
    

    So mal als Beispiel, ich kann dir noch nciht mal sagen ob ich da Fehler drin habe, ich hab das so micht getestet. Es soll ja nur veranschaulichen wie ich das ganze erstellen würde.

    Wenn du dann konsequent die Hirarchie einhällst dann brauchst du nur eine Funktion in Flughäfen zu integrieren und diese ruft dann einfach nur wiederum Funktionen der Klasse Airport auf in dem du einfach den vector durchläufst und für jeden Airport die entstrechende Funktion auf rufst, also zum beispiel ein vergleich ob das der gesuchte Flughafen ist.



  • Dieser Beitrag wurde gelöscht!


  • #include <limits>
    #include <cstdlib>
    #include <iterator>
    #include <vector>
    #include <string>
    #include <fstream>
    #include <iostream>
    #include <algorithm>
    
    class airport_t
    {
    	std::string iata;
    	std::string name;
    	std::string city;
    	std::string state;
    	std::string country;
    	double latitude   = std::numeric_limits<double>::quiet_NaN();
    	double longitude  = std::numeric_limits<double>::quiet_NaN();
    
    public:
    	airport_t() = default;
    	airport_t(std::string iata, std::string name, std::string city, std::string state, std::string country, double latitude, double longitude)
    	: iata       { iata      },
    	  name       { name      },
    	  city       { city      },
    	  state      { state     },
    	  country    { country   },
    	  latitude   { latitude  },
    	  longitude  { longitude }
    	{}
    
    	friend
    	std::istream& operator>>(std::istream &is, airport_t &airport)
    	{
    		airport_t temp;
    		std::string latitude;
    		std::string longitude;
    
    		if (!(std::getline(is, temp.iata, ',') && std::getline(is, temp.name, ',') && std::getline(is, temp.city, ',') &&
    		      std::getline(is, temp.state, ',') && std::getline(is, temp.country, ',') && std::getline(is, latitude, ',') &&
    		      std::getline(is, longitude)))
    		{
    			return is;
    		}
    
    		try {
    			temp.latitude   = std::stod(latitude);
    			temp.longitude  = std::stod(longitude);
    		}
    		catch (...) {
    			is.setf(std::ios::failbit);
    			return is;
    		}
    
    		airport = temp;
    		return is;
    	}
    
    	friend
    	std::ostream& operator<<(std::ostream &os, airport_t const &airport)
    	{
    		return os << airport.iata << ", " << airport.name << ", " << airport.city << ", " << airport.state << ", "
    		          << airport.country << ", " << airport.latitude << ", " << airport.longitude;
    	}
    };
    
    int main()
    {
    	char const *input_filename { "airports.txt" };
    	std::ifstream input_file   { input_filename };
    
    	if (!input_file.is_open()) {
    		std::cerr << "Couldn't open \"" << input_filename << "\" for reading :(\n\n";
    		return EXIT_FAILURE;
    	}
    
    	// discard first line:
    	input_file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    	
    	// read:
    	std::vector<airport_t> airports { std::istream_iterator<airport_t>{ input_file }, std::istream_iterator<airport_t>{} };
    
    	// write:
    	std::copy(airports.begin(), airports.end(), std::ostream_iterator<airport_t>{ std::cout, "\n" });
    }
    

    Um die Anführungszeichen musst Du Dich selbst kümmern.



  • @Swordfish Wow vielen dank dafür.
    Das kann ich ja ohne viel Aufwand auch für andere Aufgaben dieser Art verwenden, natürlich Variablen ändern und gucken ob anstatt Kommata, Punkte oder Tabs verwendet wurden. Vielen dank an alle, hab das ganze jetzt denke ich gut genug Verstanden^^


Anmelden zum Antworten