Textdatei nach Variablen filtern. (einfachere Methode?)



  • Hallo, ich habe eine Textdatei, die wie folgt aufgebaut ist:
    [url]
    https://www.fbi.h-da.de/fileadmin/personal/j.arz/PAD2/Katasteramt.txt[/url]

    jetzt muss ich die Textdate nach den Variablen Grundbuch, Gemarkung, Wirtschaftsart, Größe, sowie Lage filtern. So sieht mein Code bisher aus:

    void Grundstuecksverwaltung::einlesen()
    {
    	gListe = new GrundstueckListe;
    
    	fstream mystream("katasteramt.txt");
    	string buffer;
    
    	string grundbuch;
    	string gemarkung;
    	string wirtschaftsart;
    	double groesse;
    	string lage;
    
    	getline(mystream, buffer);
    
    	getline(mystream, buffer, ' ');
    	getline(mystream, buffer, ' ');
    
    	getline(mystream, buffer, '\n');
    
    	grundbuch = buffer;
    
    	for (int i = 0; i < 4; i++)
    	{
    		getline(mystream, buffer);
    	}
    
    	while (!mystream.eof()){
    		getline(mystream, buffer);
    		getline(mystream, buffer, ' ');
    		if (buffer.size() > 0){                //nach leerzeichen abfragen
    			if (buffer.size() > 0){
    				if (buffer.at(0) == '*')
    				{
    					getline(mystream, buffer, ' ');
    					getline(mystream, buffer, '\n');
    					grundbuch = buffer;
    					for (int i = 0; i < 5; i++)
    					{
    						getline(mystream, buffer);
    					}
    
    					getline(mystream, buffer, ' ');
    
    					//mystream.clear(); // clear stream flags and error state
    					//mystream.seekg(0, ios::beg); // reset read position
    				}
    			}
    
    			gemarkung = buffer;
    
    			getline(mystream, buffer, ' ');
    
    			while (buffer.size() == 0)
    			{
    				getline(mystream, buffer, ' ');
    			}
    
    			wirtschaftsart = buffer;
    
    			getline(mystream, buffer, ' ');
    
    			while (buffer.size() == 0)
    			{
    				getline(mystream, buffer, ' ');
    			}
    
    			groesse = atof(buffer.c_str());
    
    			getline(mystream, buffer);
    
    			lage = buffer.substr(9, buffer.size());
    
    			GrundstueckElement* element = new GrundstueckElement;
    			element->setGrundbuch(grundbuch);
    			element->setGemarkung(gemarkung);
    			element->setWirtschaftsart(wirtschaftsart);
    			element->setGroesse(groesse);
    			element->setLage(lage);
    
    			gListe->insertLast(element);
    
    		}
    		else{ break; }
    	}
    }
    

    Meine Frage wäre, ob es eine einfachere Methode gibt die Textdatei zu filtern. Z.b. nerven mich die getlines -

    if (buffer.size() > 0)
    

    ich suche eine elegantere Methode um das Problem zu lösen. Wäre toll, wenn mir da jemand helfen könnte.

    LG 🙂




  • Mod

    Jetzt hast du zwei extrem unterschiedliche Formate gezeigt. Wo ist denn da die Gemeinsamkeit? Ich war ja beim ersten Beitrag davon ausgegangen, dass die Breite der Einträge immer gleich ist. Das zweite Format hingegen sieht recht kompliziert aus.

    Manuelle Speicherverwaltung brauchst du hier höchstwahrscheinlich nicht. Dein Programm sollte hinterher ungefähr so aussehen (ich erspare mir mal die Übersetzung des Behördendeutschs):

    class Grundbucheintrag
    {
      std::string gemarkung;
      std::string wirtschaftsart;
      std::string lage;
      double groesse;
      friend std::istream& operator>>(std::istream&, Grundbucheintrag&);
    };
    
    class Grundbuch
    {
      std::string gemeinde;
      std::vector<Grundbucheintrag> eintraege;
      friend std::istream& operator>>(std::istream&, Grundbuch&);
    };
    
    istream& operator>>(istream& in, Grundbucheintrag& eintrag)
    {
      // Genaues Aussehen unbekannt, da Format unklar
    }
    
    istream& operator>>(istream& in, Grundbuch& grundbuch)
    {
      // Genaues Aussehen unbekannt, da Format unklar, aber besteht vermutlich aus:
    
      lesen_des_headers();
    
      for (Grundbucheintrag eintrag; in >> eintrag; )
        grundbuch.eintraege.push_back(eintrag);
    
      if (!in.eof())
        in.clear();
    
      return in;
    }
    
    int main()
    {
      ifstream kataster("Katasteramt.txt");
      std::vector<Grundbuch> grundbuecher;
      for(Grundbuch grundbuch; kataster >> grundbuch; )
        grundbuecher.push_back(grundbuch); 
    }
    


  • Wenn ich aus der Textdatei herauskopiere, werden die Leerzeichen und Tabs leider wegeditiert. Zwischen den Gemarkungen, der Wirtschaftsart und Lage sind z.B. mehrere Leerzeichen. Ich suche schon nach einer Möglichkeit um es hier richtig anzeigen zu lassen. Tut mir erst mal leid für die Verwirrung...





  • Warum nimmst du nicht deinen Text, schmeißt überflüssige Einträge raus und stellst ihn hier mit Code-Tags rein?



  • .. habe mal den Vorschlag von SeppJ aufgegriffen:

    #include <iostream>
    #include <fstream>
    #include <limits>
    #include <string>
    #include <list>
    
    struct GrundstueckElement
    {
        std::string Grundbuch;
        std::string Gemarkung;
        std::string Wirtschaftsart;
        std::string Lage;
        double Groesse;
    };
    
    // --   liest einen Text ein, der auch von White-Space-Character
    //      unterbrochen werden darf; bis Zeilenende oder einer Ziffer
    struct text
    {
        explicit text( std::string& str ) : str_( str ) {}
        std::string& str_;
    };
    std::istream& operator>>( std::istream& in, text t );
    
    // --   liest ein 'GrundstueckElement'
    std::istream& operator>>( std::istream& in, GrundstueckElement& g )
    {
        in >> g.Gemarkung >> text(g.Wirtschaftsart) >> g.Groesse;
        getline( in >> std::ws, g.Lage );
        return in;
    }
    
    std::istream& skipline( std::istream& in ) // überliest eine Zeile
    {
        return  in.ignore( std::numeric_limits< std::streamsize >::max(), '\n' );
    }
    std::istream& skipword( std::istream& in ) // überliest ein Wort
    {
        return (in >> std::ws).ignore( std::numeric_limits< std::streamsize >::max(), ' ' );
    }
    
    // --   liest den Grunbuchheader, falls vorhanden, sonst tue nichts! 
    struct GrundbuchHeader
    {
        GrundbuchHeader( std::string& str ) : str_( str ) {}
        std::string& str_;
    };
    std::istream& operator>>( std::istream& in, GrundbuchHeader gh )
    {
        char c;
        if( in >> c )
        {
            if( c == '*' )  // Grundbuch-Eintrag beginnt
            {
                getline( in >> skipline >> skipword >> skipword >> std::ws, gh.str_ );
                for( int zeile=0; zeile<4; ++zeile ) // 4 weitere Zeilen überspringen
                    in >> skipline;
            }
            else
                in.putback(c); // zu viel gelesenes Zeichen zurück stellen
        }
        return in;
    }
    
    int main()
    {
        using namespace std;
        std::list< GrundstueckElement > liste;
        ifstream in("kataster.txt");
        if( !in.is_open() )
        {
            cerr << "Fehler beim Oeffnen der Datei" << endl;
            return -2;
        }
        string grundbuch;
        for( GrundstueckElement ge; in >> GrundbuchHeader(grundbuch) >> ge; )
        {
            ge.Grundbuch = grundbuch;
            liste.push_back( ge );
        }
        if( in.eof() )
            cout << "Ok - Dateiende erreicht" << endl;
        cout << liste.size() << " Eintraege gelesen" << endl;
        return 0;
    }
    

    das wirkliche Problem war der letzte Eintrag, wo die Wirtschaftsart aus mehr als einem Wort besteht (' 2620/1745 Grünland. Wiese 87.85 '). Dazu musste dann das Helferlein text her (s. oben Zeile 28)

    std::istream& operator>>( std::istream& in, text t )
    {
        std::istream::sentry ok( in );
        if( ok )
        {
            std::ios_base::iostate state = std::ios_base::goodbit;
            try
            {
                typedef std::istream::traits_type Traits;
                std::string str;
                std::string::size_type len = 0;
                const std::ctype< char >& ct = std::use_facet< std::ctype< char > >( in.getloc() );
                for( Traits::int_type m = in.rdbuf()->sgetc(); ; m = in.rdbuf()->snextc() )
                {
                    if( Traits::eq_int_type( m, Traits::eof() ) )
                    {
                        state |= std::ios_base::eofbit;
                        break;
                    }
                    const char c = Traits::to_char_type( m );
                    if( ct.is( std::ctype_base::digit, c ) || c == '\n' )
                        break;
                    str.append( 1, c );
                    if( !ct.is( std::ctype_base::space, c ) )
                        len = str.length();
                }
                t.str_ = str.substr( 0, len );
            }
            catch(...)
            {
                state |= std::ios_base::badbit;
                if( in.exceptions() & std::ios_base::badbit )
                    throw;
            }
            in.setstate( state );
        }
        return in;
    }
    

    zum Thema "wie funktioniert operator>>( std::istream& in, text t )?" siehe auch hier: http://www.c-plusplus.net/forum/p2256837#2256837



  • Formuliere doch das Dateiformat erst mal als (E)BNF, macht vieles leichter.


Log in to reply