Brüche (z/n) zeilenweise aus datei einlesen



  • Hey

    Ich suche schon seit Stunden nach einer Lösung, aber so richtig fündig werde ich nicht. Überall steht was Anderes, außerdem will ich das Ganze ja nachvollziehen können.
    Ich soll Brüche aus einer Datei einlesen können, diese soll in etwa so aussehen:

    1/1
    1/2
    24/92
    3/1
    ...
    

    Ich habe also pro Zeile einen Bruch stehen.

    Am Ende möchte ich Zähler und Nenner in einer Variable (long int) haben.
    Wie bekomme ich es also hin, das ich die Zahl vor, und die Zahl nach dem Bruchstrich in eine Variable speichern kann (mit denen rechne ich dann weiter ...), dann springe ich zur nächsten Zeile und speichere die nächsten zwei Werte usw., bis die letzte Zeile erreicht ist.

    Ich hoffe ihr versteht wie ich das meine 🙂


  • Mod

    Stundenlang? Es gäbe zwar auch elegantere Lösungen, aber für folgendes braucht man nur das Wissen aus den ersten beiden Kapiteln eines jeden C++-Buchs.

    cin >> zaehler >> bruchstrich >> nenner;
    

    Wobei bruchstrich eine char-Variable ist.



  • Ich vermute, dass du genau danach suchst, wie man Brüche aus Dateien einlesen kann. Solche sehr speziellen Fragen und Antworten / Lösungen wirst du aber meistens nie finden, da mit halbwegs guten C++ Kenntnissen man das selber programmieren kann.

    Du müsstest z.B. nach soetwas suchen wie "Wie öffne ich eine Datei".
    Auf Youtube kann ich dir die Tutorials von Brotcrunsher und Bytes'n'Objects heißt er glaub ich, empfehlen.

    Als kleine Beispiellösung hätte ich folgendes, eigentlich selbsterklärendes Programm:

    #include <iostream>
    #include <string>
    #include <fstream>
    #include <vector>
    #include <exception>
    
    // zahlen als character
    char numbers[]{
    	'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'
    };
    
    // funktion zum ausgeben
    template<typename T>
    void call(T data) {
    	std::cout << data << std::endl;
    }
    
    struct Fraction {
    
    	// zähler
    	long numerator;
    
    	// nenner
    	long denominator;
    
    	// standard konstruktor wird wegen std::vector benötigt
    	Fraction() {
    		numerator = 1;
    		denominator = 1;
    	}
    
    	Fraction(const std::string& input) {
    
    		std::string numeratorString = "", denominatorString = "";
    		bool slashReached = false;
    
    		// gehe jeden character in der eingelesenen zeile durch
    		for (int i = 0; i < input.length(); i++) {
    
    			// überprüfe, ob der character eine zahl oder schrägstrich ist
    			for (int j = 0; j < 10; j++) {
    
    				// wurde der schrägstrich noch nicht erreicht, füge die zahl dem zähler hinzu
    				if (input[i] == numbers[j] && !slashReached)
    					numeratorString += numbers[j];
    
    				// wurde der schrägstrich erreicht, füge die zahl dem nenner hinzu
    				else if (input[i] == numbers[j] && slashReached)
    					denominatorString += numbers[j];
    
    				// speichere es, wenn der schrägstrich erreicht wurde
    				else if (input[i] == '/')
    					slashReached = true;
    
    				else
    					throw std::exception("zeile konnte nicht in bruch umgewandelt werden");
    			}
    		}
    
    		// umwandlung von string in long
    		numerator = std::stol(numeratorString);
    		denominator = std::stol(denominatorString);
    
    	}
    
    	// überprüfung, ob ein character eine zahl beinhaltet
    	static bool isNumber(char number) {
    		for (int i = 0; i < 10; i++) {
    			if (number == numbers[i]) {
    				return true;
    			}
    		}
    		return false;
    
    	}
    
    	// überprüfung, ob eine zeile ein bruch ist
    	static bool isFraction(const std::string& input) {
    		for (int i = 0; i < input.length(); i++) {
    			for (int j = 0; j < 10; j++) {
    				if (isNumber(input[i]) || input[i] == '/') {
    					break;
    				} else {
    					return false;
    				}
    			}
    		}
    		return true;
    	}
    
    	// überladener ausgabe operator
    	friend std::ostream& operator<<(std::ostream& out, Fraction fraction) {
    		out << fraction.numerator << "/" << fraction.denominator;
    		return out;
    	}
    
    };
    
    int main(int argc, char** argv) {
    
    	// erzeuge einen input stream der datei datei.txt und öffne sie
    	std::ifstream file("datei.txt");
    
    	// dynamisches array zum speichern der brüche
    	std::vector<Fraction> fractions(0);
    
    	// wenn die datei geöffnet wurde
    	if (file.is_open()) {
    
    		std::string line;
    
    		// lese eine zeile des input streams und speichere die zeile in line
    		while (std::getline(file, line)) {
    
    			// entspricht die zeile einem bruch
    			if (Fraction::isFraction(line)) {
    
    				// erstelle einen bruch
    				Fraction fraction(line);
    
    				// füge ihn dem array hinzu
    				fractions.push_back(fraction);
    			}
    		}
    
    	} else {
    		// sonst gib eine fehlermeldung aus
    		call("Konnte die Datei nicht oeffnen.");
    	}
    
    	// gib alle brüche aus
    	for (auto& fraction : fractions)
    		call(fraction);
    
    	system("pause");
    	return 0;
    }
    


  • Da steht so viel Quatsch, das würde ich nicht Lösung nennen...



  • DocShoe schrieb:

    Da steht so viel Quatsch, das würde ich nicht Lösung nennen...

    Dann kannst du es gerne berichtigen, wäre doch gut für ihn, wenn er eine bessere Lösung bekommen würde.



  • Solix0x schrieb:

    Dann kannst du es gerne berichtigen, wäre doch gut für ihn, wenn er eine bessere Lösung bekommen würde.

    Struct und vector sind schon mal gut, kombiniert mit SeppJs Vorschlag ergäbe das

    #include <fstream>
    #include <iostream>
    #include <vector>
    
    struct Fraction
    { 
    	// zähler 
    	long numerator; 
    	// nenner 
    	long denominator; 
    //	Fraction() : numerator(1), denominator(1) {} // nicht nötig
    };
    
    std::istream& operator>>(std::istream& in, Fraction& f) 
    { 
    	char slash;
    	in >> f.numerator >> slash >> f.denominator;
    	return in;
    }
    
    std::ostream& operator<<(std::ostream& o, Fraction& f)
    { 
    	o << f.numerator << '/' << f.denominator;
    	return o; 
    } 
    
    int main()
    { 
    	using namespace std; 
    	vector<Fraction> fractions;
    	ifstream datei("fractions.txt"); 
    	if(!datei.is_open()) 
    	{ 
    		cout << "Die Datei nicht geoeffnet werden.\n";
    		return 0; 
    	} 
    	for(Fraction f; datei >> f;)
    	{
    		fractions.push_back(f);
    		cout << f << '\n';
    	}
    }
    

    Der TE wollte das in anderer Form haben, das bleibt ja noch als Übung.



  • In dem operator>> sollte man aber noch prüfen, dass der gelesene Slash wirklich ein solcher war und ansonsten das failbit setzen.



  • Hallo Solix0x,

    Solix0x schrieb:

    Auf Youtube kann ich dir die Tutorials von Brotcrunsher und Bytes'n'Objects heißt er glaub ich, empfehlen.

    wenn Du diese Videos gesehen hast, warum liest Du dann einen Bruch als String in den Speicher und fängst dann zu Fuß an,ihn als Zahl zu interpretieren? Die Videos zeigen doch schon früh - so zwischen 6.-8.Folge - wie man Zahlen einliest.

    Wie kommst Du zu getline und string-Fieselei? Wird das dort in späteren Videos so gezeigt? Die eine Zeile, die SeppJ vorgeschlagen hat, ersetzt ungefähr 2/3 Deines Codes.

    Gruß
    Werner


Anmelden zum Antworten