Aus einer Textdatei Zeichen nach jedem Komma einzeln auslesen



  • Hallo Leute,

    habe mir jetzt extra ein Account hier erstellt, damit mir vieleicht hier jemand helfen kann, da ich schon seit 3 Tagen verzweifelnd versuche
    aus einer text Data verschiede Zahlen die mit einem Koma getrennt sind einzeln aufzurufen. Doch noch bin ich auf keine Lösung gekommen.

    Ich versuche ein Spiel mit C++ und SFML zu erstellen und um eine TileMap für das Spiel zu erstellen brauche ich diese Zahlen einzeln damit das Programm weiß welches Bild es ausschneiden und
    zeichnen soll.
    Die Daten für diese TileMap werden so abgefragt:

    Tile: Tile.png;
    TileSizeWidth: 32;
    TileSizeHeight: 32;
    MapSizeWidth: 9;
    MapSizeHeight: 9;
    Data: 1, 2, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 1, 11, 1, 1, 1, 1, 1, 1, 16, 2, 6, 2, 17, 1, 1, 1, 1, 11, 1, 11, 1, 11, 1, 1, 2, 2, 6, 2, 6, 2, 6, 2, 2, 1, 1, 11, 1, 11, 1, 11, 1, 1, 1, 1, 12, 2, 6, 2, 7, 1, 1, 1, 1, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 1, 11, 1, 1, 1, 1;

    Für die ersten 5 Zeilen ist es einfach da nutze ich die getLine Funktion und alles klappt

    std::ifstream ReadTextFile("Maps\\map1.map", std::ios::in);
    		std::string temp;
    
    		std::string RightValue;
    		char CurrentLine[256];
    		if (ReadTextFile.good())
    		{
    		//TileSet
    		std::getline(ReadTextFile, temp);
    		RightValue.append(CurrentLine);
    		std::size_t begin = temp.find_first_of(": ");
    		std::size_t end = temp.find_last_of("; ");
    		std::size_t len = end - begin;
    		temp = temp.substr(begin + 1, len - 1);
    		/*this->tileSet = std::stoi(temp, nullptr);*/ // funktionier nicht!, Programm stürtz ab, liegt wohl daran, dass es ein String ist und kein int
    		//TileSizeWith
    		std::getline(ReadTextFile, temp);
    		begin = temp.find_first_of(": ");
    		end = temp.find_last_of(";");
    		len = end - begin;
    		temp = temp.substr(begin + 1, len - 1);
    		this->tileWidth = std::stoi(temp, nullptr);
    		//TileSizeHeight
    		std::getline(ReadTextFile, temp);
    		begin = temp.find_first_of(": ");
    		end = temp.find_last_of(";");
    		len = end - begin;
    		temp = temp.substr(begin + 1, len - 1);
    		this->tileHeight = std::stoi(temp, nullptr);
    		//With
    		std::getline(ReadTextFile, temp);
    		begin = temp.find_first_of(": ");
    		end = temp.find_last_of(";");
    		len = end - begin;
    		temp = temp.substr(begin + 1, len - 1);
    		this->width = std::stoi(temp, nullptr);
    		//Height
    		std::getline(ReadTextFile, temp);
    		begin = temp.find_first_of(": ");
    		end = temp.find_last_of(";");
    		len = end - begin;
    		temp = temp.substr(begin + 1, len - 1);
    		this->height = std::stoi(temp, nullptr);
    		//Data 
    		std::getline(ReadTextFile, temp);
    		...		
    		ReadTextFile.close();
    		}
    

    Nun möchte ich auch die Zahlen in der 6. Zeile abfragen, jedoch einzeln, dabei auch immer die Komas überspringen und da komme ich nicht mehr weiter. Das einzigste was mir noch einfällt ist die ganzen Zahlen einzeln in eine eigene Zeile zu bringen und in
    einer Schleife jedes mal getline aufzurufen und dort mit den Zahlen die Tiles zu positionieren und mit sf::Rect(sf::intrect(x,y,x,y)) das Passende Bild ausschneiden, doch diese Methode finde ich
    blöd, da ich somit jede Zahl einzeln immer wieder in eine eigene Zeile packen muss, und wenn ich mit dem Programm Tiled wieder was verändern muss, muss ich wieder alles von vorne machen.

    Da hoffe ich, das jemand mir dabei helfen kann.


  • Mod

    Ich verstehe deine Problemstellung nicht. Hast du Probleme mit dem Lesevorgang oder mit der Verwaltung deiner Daten? Insbesondere dies ist mir rätselhaft:

    Das einzigste was mir noch einfällt ist die ganzen Zahlen einzeln in eine eigene Zeile zu bringen und in
    einer Schleife jedes mal getline aufzurufen und dort mit den Zahlen die Tiles zu positionieren und mit sf::Rect(sf::intrect(x,y,x,y)) das Passende Bild ausschneiden, doch diese Methode finde ich
    blöd, da ich somit jede Zahl einzeln immer wieder in eine eigene Zeile packen muss, und wenn ich mit dem Programm Tiled wieder was verändern muss, muss ich wieder alles von vorne machen.

    Kannst du das mal so beschreiben, dass das auch jemand versteht, der nicht bereits weiß, was du überhaupt machst?

    Ansonsten: Was soll der Quatsch mit den char-Arrays, stoi usw? Nimm doch einfach den Stream Operator>> und gut ist. Oder wenigstens std::string statt char-Arrays. Insgesamt kommt mir deine jetzige Methode (für die ersten paar Zeilen) furchtbar frickelig und unzuverlässig vor. Zig mal der gleiche Code mit kleinen Änderungen, keinerlei Fehlerprüfungen und so. Dabei wäre das alles mehr oder weniger automatisch erledigt, wenn du einfach die fertigen Lesemethoden benutzen würdest, anstatt dir selber etwas zu basteln. Falls dein Problem mit den Zahlen beim Lesen derselben liegen sollte, dann ist dies auch die Lösung dafür.



  • @SeppJ

    Ich weiß das der Code nicht perfekt ist, denn zum einen bin ich in der lernphase und zweitens will ich erst mein Problem lösen bis ich dann mit Funktionen
    und schleifen das ganze vereinfache und den Code kleiner mache.

    Zu meinem Problem

    ich will einfach aus einer externen Datei(txt) verschieden Zahlen auslesen
    In der .txt Datei stehen z.b solche Zahlen

    5,3,1,1,1,2,3,4,5,6,7

    Nun möchte ich in einer Schleife jede Zahl einmal Aufrufen, ein Koma übersprigen und im nächsten loop die nächste Zahl lesen.
    Heißt,wenn ich jedes mal mit cout die Zahl ausgebe
    sollte es im cmd Fenster so aussehen
    5
    3
    1
    1
    1
    2
    3
    4
    5
    6
    7

    Damit ich dann in dieser Schleife mit den zahlen arbeiten kann
    if(Zahl == 1){...}
    if(Zahl == 2){...}
    if(Zahl == 3){...}
    if(Zahl == 4){...}

    ich hoffe du hast es jetzt einigermaßen verstanden


  • Mod

    while((stream >> zahl >> zeichen) && zeichen == ',') verarbeite(zahl);
    

    ?



  • Ich danke dir! Endlich klappt es.



  • Wie macht man das eigentlich wirklich?

    sowas?

    #include <algorithm>
    #include <vector>
    #include <string>
    #include <fstream>
    #include <iostream>
    
    typedef enum entry_id_tag { EI_TITLE, EI_TILE_SIZE_WIDTH, EI_TILE_SIZE_HEIGHT, EI_MAP_SIZE_WIDTH, EI_MAP_SIZE_HEIGHT, EI_DATA, EI_UNKNOWN } entry_id_t;
    std::string entry_names[] = { "Tile:", "TileSizeWidth:", "TileSizeHeight:", "MapSizeWidth:", "MapSizeHeight:", "Data:" };
    
    entry_id_t get_entry_id( std::string const & entry_name )
    {
    	auto result{ std::find( std::begin( entry_names ), std::end( entry_names ), entry_name ) };
    	return static_cast< entry_id_t >( result == std::end( entry_names ) ? EI_UNKNOWN : result - entry_names );
    }
    
    typedef struct tile_data_tag {
    	std::string title;
    	unsigned tile_size_width;
    	unsigned tile_size_height;
    	unsigned map_size_width;
    	unsigned map_size_height;
    	std::vector< unsigned > data;
    } tile_data_t;
    
    template< typename T >
    bool try_read( std::istream & is, T & value, char delim = ';' )
    {
    	char ch;
    	if( ( is >> std::skipws >> value >> ch ) && ch == delim )
    		return true;
    	return false;
    }
    
    int main()
    {
    	std::ifstream is{ "test.txt" };
    	std::string entry_name;
    	tile_data_t tile_data;
    	bool error = false;
    
    	while( is >> std::skipws >> entry_name ) {
    
    		switch( get_entry_id( entry_name ) ) {
    			case EI_TITLE:
    				if( !( is >> tile_data.title ) )
    					error = true;
    				break;
    
    			case EI_TILE_SIZE_WIDTH:
    				if( !try_read( is, tile_data.tile_size_width ) )
    					error = true;
    				break;
    
    			case EI_TILE_SIZE_HEIGHT:
    				if( !try_read( is, tile_data.tile_size_height ) )
    					error = true;
    				break;
    
    			case EI_MAP_SIZE_WIDTH:
    				if( !try_read( is, tile_data.map_size_width ) )
    					error = true;
    				break;
    
    			case EI_MAP_SIZE_HEIGHT:
    				if( !try_read( is, tile_data.map_size_height ) )
    					error = true;
    				break;
    
    			case EI_DATA:
    			{
    				unsigned value;
    				while( try_read( is, value, ',' ) )
    					tile_data.data.push_back( value );
    				tile_data.data.push_back( value );
    				break;
    			}
    
    			default:
    				error = true;
    		}
    
    		if( error )
    			is.close();
    	}
    
    	if( !error ) {
    
    		std::cout << entry_names[ EI_TITLE ] << ' ' << tile_data.title << '\n'
    			<< entry_names[ EI_TILE_SIZE_WIDTH ] << ' ' << tile_data.tile_size_width << '\n'
    			<< entry_names[ EI_TILE_SIZE_HEIGHT ] << ' ' << tile_data.tile_size_height << '\n'
    			<< entry_names[ EI_MAP_SIZE_WIDTH ] << ' ' << tile_data.map_size_width << '\n'
    			<< entry_names[ EI_MAP_SIZE_HEIGHT ] << ' ' << tile_data.map_size_height << '\n'
    			<< entry_names[ EI_DATA ] << ' ';
    
    		for( auto const & i : tile_data.data )
    			std::cout << i << ' ';
    
    		std::cout << "\n\n";
    
    	} else std::cerr << "Format error!\n\n";
    }
    


  • Swordfish schrieb:

    Wie macht man das eigentlich wirklich?

    Hm. Das war schon als ernste Frage gedacht ...



  • Vielleicht sind 4 Stunden warten am Freitag Nachmittag nicht genug?


  • Mod

    Swordfish schrieb:

    Swordfish schrieb:

    Wie macht man das eigentlich wirklich?

    Hm. Das war schon als ernste Frage gedacht ...

    Normalerweise fängt man damit an, sich die Datenstrukturen gut zu überlegen. Dieser Schritt scheint hier nicht wirklich erfolgt zu sein und ohne komplette Problembeschreibung kann man es auch nicht für jemand anderen erledigen. Und dann kann man sich überlegen, wie man diese Datenstrukturen serialisiert und deserialisiert.



  • Durch die ";" wird die Sache eigentlich eh sehr einfach - muss man sich nichtmal mit dem in C++ etwas lästigen "line breaks are whitespace" Thema befassen.



  • hustbaer schrieb:

    Vielleicht sind 4 Stunden warten am Freitag Nachmittag nicht genug?

    Sorry.


Log in to reply