*.txt file bis zeilenumbruch einlesen



  • hallo,

    ich möchte ein textfile wo zahlen durch semikolon getrennt drin stehen bis zum zeilenumbruch einlesen und die zahlen dann in ein array schreiben. das ganz sollte dabei dynamisch funktionieren da ich vorher nicht weiß wieviele zahlen in einer zeile stehen.

    wäre cool wenn mir jemand helfen könnte, weiß nicht mehr weiter.

    danke schonmal

    grüße jeannine



  • Hallo

    Such mal nach der Funktion getline() aus dem Header <string>

    chrische



  • Hallo,

    dann hab ich ja aber die ganze Zeile als String. Wie krieg ich dann die Zahlen in mein Array?

    Gibt es eine Möglichkeit die Zeile gleich mit den Zahlen einzulesen?

    Danke für die schnelle Antwort

    Gruß



  • Wenn du die Zahlen nicht durch Semikolon trennst ist dies durchaus möglich. Dies kannst du beispielsweise wie folgt realisieren

    fstream file("foo.txt");
    vector<int> vec;
    int a;
    while(file>>a){
    vec.push_back(a);  //Beispielsweise wenn du alles in nem Vektor speichern willst
    }
    

    Dann liest er alles einzeln ein das durch Leerzeichen getrennt ist und schreibt es nach und nach in a.

    MFG
    chewbo



  • wahrscheinlich viiiiel zu kompliziert und unnütz, aber so in etwa habe ich das irgendwann mal gemacht:

    vector<int> demoFkt( const string &file )
    {
    	ifstream fin;
    	fin.open( file.c_str(), ios_base::in );
    	if( !fin )
    		return vector<int>();
    
    	char c = 'a';
    	string zahl;
    	vector<int> vec;
    	while( !fin.eof() )
    	{
    		fin.get( c );
    		if( c != '\n' && c != ';' )
    			zahl += c;
    		else if( c == ';' || c == '\n' )
    		{
    			vec.push_back( atoi( zahl.c_str() ) );
    			zahl.clear();
    			if( c == '\n' )
    				break;
    		}
    	}
    	fin.close();
    	return vec;
    }
    

    mfg,
    julian



  • chewbo schrieb:

    Wenn du die Zahlen nicht durch Semikolon trennst ist dies durchaus möglich. Dies kannst du beispielsweise wie folgt realisieren

    fstream file("foo.txt");
    vector<int> vec;
    int a;
    while(file>>a){
    vec.push_back(a);  //Beispielsweise wenn du alles in nem Vektor speichern willst
    }
    

    Dann liest er alles einzeln ein das durch Leerzeichen getrennt ist und schreibt es nach und nach in a.

    MFG
    chewbo

    oder in dem fall die semikola durch leerzeichen ersetzen dann hauts auch hin ;).



  • ...alternativ kannst du auch die ganze zeile als einen string einlesen und ne funktion schreiben, die immer bei nem smeikolon trennt (und dann z.B. zu int umwandelt).

    mfg,
    julian



  • Konnte man beim operator>> von ifstream/fstream nicht festlegen bei welchem Zeichen er unterbricht? (Standard ist es ja das Leerzeichen) Ich hab da sowas in Erinnerung, bin mir aber nicht mehr sicher.



  • vielleicht hilft das hier?



  • Shinja schrieb:

    Konnte man beim operator>> von ifstream/fstream nicht festlegen bei welchem Zeichen er unterbricht? (Standard ist es ja das Leerzeichen) Ich hab da sowas in Erinnerung, bin mir aber nicht mehr sicher.

    Afaik nein - op>> liest generell bis zum ersten Whitespace, das er findet (außer du änderst da eine Einstellung ganz tief in den Locales). Aber bei getline() kannst du festlegen, welches Zeichen er als "Zeilenende" verwenden soll.



  • Ah, danke CStoll, dann habe ich die beiden durcheinander geworfen.
    Eine Frage noch dann dazu: Wenn man getline nun sagt, er soll als Unterbrechungszeichen ein ';' nehmen, liest der das newline zeichen dann einfach ein? Koennte man quasi ein
    2;3;6;1;6;
    6;3;6;1;99;23;
    usw. dann einfach einlesen indem man getline als Unterbrechzeichen ; uebergibt? Oder wird dann auch ein \n eingelesen? (in diesem Beispiel machts keinen Sinn, ich weiss, ist nur Interessehalber)



  • Wenn du getline() ein anderes Begrenzungszeichen übergibst, behandelt es das \n als ganz normales Textzeichen und gibt es auch an den Aufrufer weiter (d.h. in deinem Beispiel würdest du als sechsten Wert "\n6" zurückbekommen).



  • Ok, vielen Dank, jetzt hab ichs verstanden.

    Naja, ich habe mir mittlerweile angewoehnt eh einfach einen whitespace als Trennzeichen zu nehmen im Falle von solchen Daten. Aber man weiss nie ob mans net doch mal braucht.

    (PS: Hmm, so ein angepasstes getline waere doch ganz nett um z.B HTML Tags rauszufiltern aus einem Text. Sollte ichs mal brauchen)



  • number_nine schrieb:

    ich möchte ein textfile wo zahlen durch semikolon getrennt drin stehen bis zum zeilenumbruch einlesen und die zahlen dann in ein array schreiben. das ganz sollte dabei dynamisch funktionieren da ich vorher nicht weiß wieviele zahlen in einer zeile stehen.

    Hallo Jeannine,

    das Format ist etwas ungünstig. Eine Möglichkeit besteht - wie schon erwähnt - darin, die einzelnen Zeilen mit getline zu Lesen und danach die Zahlen aus den string heraus zu lesen. Das sieht etwa so aus:

    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <string>
    #include <vector>
    
    std::istream& semikolon( std::istream& in )
    {
        char c;
        if( in >> c && c != ';' )
            in.setstate( std::ios_base::failbit );
        return in;
    }
    
    class EineZeileZahlen
    {
    public:
        typedef int value_type; // kann auch z.B. double sein
        friend std::istream& operator>>( std::istream& in, EineZeileZahlen& ezz )
        {
            using namespace std;
            string buf;
            if( getline( in, buf ) )
            {
                std::vector< value_type > zahlen;
                istringstream zeile( buf );
                // an dieser Stelle müßte man die Locale und die Flags des Original-Streams übernehmen ..
                bool first = true;
                for( value_type zahl; (first || zeile >> semikolon) && zeile >> zahl; first = false )
                    zahlen.push_back( zahl );
                if( zeile.eof() )                       // bis zum Zeilen-Ende gelesen
                    swap( ezz.m_zahlen, zahlen );       // dann ok, Daten übernehmen
                else
                    in.setstate( ios_base::failbit );   // sonst Fehler
            }
            return in;
        }
        int size() const { return m_zahlen.size(); }
    private:
        std::vector< value_type > m_zahlen;
    };
    
    int main()
    {
        using namespace std;
        ifstream file("input.txt");
        for( EineZeileZahlen ezz; file >> ezz; )
        {
            // mache was mit 'ezz'
            cout << ezz.size() << " Zahlen gelesen" << endl;
        }
        return 0;
    }
    

    Das getline ist zwar sehr beliebt, hat aber einige Nachteile. Unter anderen den, dass die evt. vorher gemachten Einstellungen am Einlese-Stream nicht mehr wirken. Eine Alternative wäre so was:

    bool isEnd( std::istream& in )
    {
        if( in.good() )
        {
            typedef std::streambuf::traits_type traits_type;
            std::streambuf* sb = in.rdbuf();
            const std::ctype< char >& ct = std::use_facet< std::ctype< char > >( in.getloc() );
            for( std::streambuf::int_type m = sb->sgetc(); ; m = sb->snextc() )
            {
                if( traits_type::eq_int_type( m, traits_type::eof() ) )
                {
                    in.setstate( std::ios_base::eofbit );
                    return true;
                }
                const char c = traits_type::to_char_type( m );
                if( !ct.is( std::ctype_base::space, c ) )
                    return false;
                if( c == '\n' )
                    break;
            }
            sb->sbumpc();
        }
        return true;
    }
    
    class EineZeileZahlen
    {
    public:
        typedef int value_type; // kann auch z.B. double sein
        friend std::istream& operator>>( std::istream& in, EineZeileZahlen& ezz )
        {
            using namespace std;
            std::istream::sentry ok( in, false );
            if( ok )
            {
                std::vector< value_type > zahlen;
                bool first = true;
                for( value_type zahl; !isEnd( in ) && (first || in >> semikolon) && in >> zahl; first = false )
                    zahlen.push_back( zahl );
                if( in )                            // kein Fehler
                    swap( ezz.m_zahlen, zahlen );   // dann ok, Daten übernehmen
            }
            return in;
        }
        int size() const { return m_zahlen.size(); }
    private:
        std::vector< value_type > m_zahlen;
    };
    

    mit der relativ komplizierten Funktion isEnd. Einfacher wird es, wenn man das Format dahingehend ändert, Whitespaces als Trenner zwischen den Zahlen zu benutzen und das Semikolon nur als Abschluß nach einer Zahlenreihe - also z.B.:

    89 78 23 -1;
    1 2;
    
    -4 9 10 2;
    
    class EineZeileZahlen
    {
    public:
        typedef int value_type; // kann auch z.B. double sein
        friend std::istream& operator>>( std::istream& in, EineZeileZahlen& ezz )
        {
            using namespace std;
            std::vector< value_type > zahlen( (istream_iterator< value_type >( in )), istream_iterator< value_type >() );
            in.clear();
            if( in >> semikolon ) // kein Fehler
                swap( ezz.m_zahlen, zahlen );   // dann ok, Daten übernehmen
            return in;
        }
        int size() const { return m_zahlen.size(); }
    private:
        std::vector< value_type > m_zahlen;
    };
    

    Gruß
    Werner


Anmelden zum Antworten