Überprüfung der Formatierung einer Textdatei beim Einlesen



  • Hallo Leute!

    Ich bin ein relativer Neuling in Sachen Programmieren. Ich hatte zwar schon einiges mit diversen Programmiersprachen in meiner Technischen Schullaufbahn zu tun, trotzdem war das nie so wirklich meins. Auf jeden Fall hab ich jetzt folgendes Problem:
    Wie schaffe ich es, die Formatierung einer eingelesenen Textdatei zu überprüfen?
    Was ich machen möchte, ist eine Textdatei einlesen, in der 3 Formen (Rechteck, Dreieck und Kreis) definiert sind. Z.b. schaut das dann bei dem Rechteck so aus:

    rectangle id="1" color="000033" x="0" y="0" width="640" height="480"
    

    Die Werte der Parameter lese ich mit fscanf ein, speichere sie in variablen und mache das in einer while Schleife bis zum Dateiende (EOF).
    Nur wie schaue ich jetzt, dass diese Formatierung auch stimmt? Sollte sie nicht stimmen, soll ein Fehlercode ausgegeben werden.
    Insgesamt steht jede Form in einer eigenen Zeile. D.h. es gibt logischerweise 3 Zeilen mit je einer Form und den jeweiligen Parametern dazu.

    Ich hoffe, ihr versteht was ich meien und könnt mir helfen! 🙂
    Danke schonmal im Voraus für die Mühe! :xmas1:

    Mfg


  • Mod

    Nun, ohne das Format genau zu kennen, kann man nur so viel sagen: Formulier die Regeln, schreib Funktionen die nach diesen Regeln die Daten zu extrahieren versuchen. Sind sie erfolgreich, so war das Format wohl richtig. Schlagen sie fehl, dann war wohl etwas falsch. Wenn du entsprechend viel Aufwand betreibst, kannst du sogar genau feststellen, was falsch war. Jedenfalls ist das Grundprinzip, dass du die Daten eben selber prüfen musst. Es gibt auch fertige Parserhilfsprogramme, mit denen du das Datenformat in einer Formatbeschreibungssprache beschreiben kannst und dann automatisch passenden Code erzeugen kannst oder die du als Bibliothek zur Datenextraktion benutzen kannst. Stichworte zum Anfang einer Internetrecherche wären zum Beispiel:
    http://en.wikipedia.org/wiki/GNU_bison
    oder
    http://en.wikipedia.org/wiki/Flex_lexical_analyser

    Als Neuling solltest du aber wohl wenigstens einmal versuchen, so etwas selber zu schreiben, ich halte das für lehrreich.



  • Mit fscanf erst den Bezeichner lesen und davon abhängig dann den Rest.





  • GuitarKing schrieb:

    Nur wie schaue ich jetzt, dass diese Formatierung auch stimmt? Sollte sie nicht stimmen, soll ein Fehlercode ausgegeben werden.

    sscanf, fscanf geben die Anzahl der konvertierten Elemente zurück, die kannst du prüfen. Wenn die erwartete Anzahl nicht stimmt, kannst du nen Fehlercode ausgeben.



  • DirkB schrieb:

    Mit fscanf erst den Bezeichner lesen und davon abhängig dann den Rest.

    Nein.
    Wenn die Formate fest sind wie beschrieben, dann 3 sscanf-Formatstrings dafür und über sscanf-Rückgabe-Auswertung die Zuordnung zu den Typen vornehmen.



  • GuitarKing schrieb:

    rectangle id="1" color="000033" x="0" y="0" width="640" height="480"
    

    Mein Gott, was ist denn daran so schwer, einfach diese Konstanz des Datenformates auszunutzen und identisch in einen Formatstring zu übertragen?

    char *s="rectangle id=\"1\" color=\"000033\" x=\"0\" y=\"0\" width=\"640\" height=\"480\"";
    unsigned a,b,c,d,e,f;
    if( 6==sscanf(s,"rectangle id=\"%u\" color=\"%x\" x=\"%u\" y=\"%u\" width=\"%u\" height=\"%u\"",&a,&b,&c,&d,&e,&f) )
      puts("OK");
    


  • Wutz schrieb:

    Mein Gott, was ist denn daran so schwer, einfach diese Konstanz des Datenformates auszunutzen und identisch in einen Formatstring zu übertragen?

    Die Idee ist gut. 👍
    Die könnte von mir sein. :p



  • Wobei hierbei sogar derselbe Formatstring für sscanf auch für (s)printf zu gebrauchen wäre, im Sinne einer Wiederverwendung.



  • Oke danke, hab das Problem mittlerweile gelöst. Nun hab ich aber ein neues.
    Und zwar habe ich ein struct definiert mit einigen variablen.
    In meiner main Funktion speichere ich eine eingelesene Variable einer Datei in eine Struct variable z.B.:

    pos_x.x = x_r;
    

    D.h. "x_r" ist die eingelesene Variable und die wird in "x" über "pos_x" in das struct gespeichert. Soweit so gut.

    Nun habe ich eine andere Funktion (getColor), in der ich eine eingelesene hexadezimal codierte RGB Farbe (übergabe an "hex_color") mit 6 Stellen von der main Funktion aufteile, um die einzelnen Farbanteile herauszufischen (mit bitshifting etc.).

    void getColor(int hex_color)
    {
      int count;
      int pos;
    
      struct FormProperties color; //definition of variable "color" of 
                                   //struct type "FormProperties"
    
      for(count=COUNTVALUE1; count<=COUNTVALUE3; count += COUNTVALUE2) //rightshift  
      {                                                                //two nibble 
    
        pos = ((hex_color>>count) & 0xff); 
    
        if(count == COUNTVALUE1)
        {
          color.color_blue = pos;
    
         //printf("Color blue = %x\n", pos);
        }
        else if(count == COUNTVALUE2)
        {
          color.color_green = pos;
          //printf("Color green = %x\n", pos);
        }
        else  if(count == COUNTVALUE3)
        {
          color.color_red = pos;
          //printf("Color red = %x\n", pos);
        }
      }
    
    }
    

    Diese Farbanteile von "pos" will ich wieder jeweils in eine struct Variable (color_red, color_green, color_blue) mit der gleichen Methode wie oben genannt speichern und in der main Funktion testweise ausgeben, um zu sehen, ob das über das struct funktioniert (da ich später diese Variablen an eine Liste weitergeben muss, wo die variablen dann weiterverarbeitet werden). Das tut es jedoch nicht. D.h. er würde mir das in der struct variable gespeicherte nur in der jeweiligen Funktion ausgeben, in der ich auch wirklich einen Wert in die Struct Variable speichere. Wieso wird nichts "global" in die struct Variable von der Funktion getColor gespeichert, sodass ich von überall darauf zugreifen kann? Mach ich da einen Denkfehler?



  • GuitarKing schrieb:

    D.h. "x_r" ist die eingelesene Variable und die wird in "x" über "pos_x" in das struct gespeichert. Soweit so gut.

    Soweit so gut? Wozu der Umweg über eine Variable, warum nicht direkt in der Struktur speichern?

    GuitarKing schrieb:

    Nun habe ich eine andere Funktion (getColor), in der ich eine eingelesene hexadezimal codierte RGB Farbe (übergabe an "hex_color") mit 6 Stellen von der main Funktion aufteile, um die einzelnen Farbanteile herauszufischen (mit bitshifting etc.).

    Dafür brauchst du weder for Schleife noch if/else Anweisungen.

    unsigned hex_color = 0xAABBCCDD;
    	printf ( "%x %x %x %x\n", hex_color>>24, (hex_color>>16) & 0x00FF, (hex_color >> 8) & 0x00FF, hex_color & 0x00FF );
    

    GuitarKing schrieb:

    Diese Farbanteile von "pos" will ich wieder jeweils in eine struct Variable (color_red, color_green, color_blue) mit der gleichen Methode wie oben genannt speichern und in der main Funktion testweise ausgeben, um zu sehen, ob das über das struct funktioniert (da ich später diese Variablen an eine Liste weitergeben muss, wo die variablen dann weiterverarbeitet werden). Das tut es jedoch nicht. D.h. er würde mir das in der struct variable gespeicherte nur in der jeweiligen Funktion ausgeben, in der ich auch wirklich einen Wert in die Struct Variable speichere. Wieso wird nichts "global" in die struct Variable von der Funktion getColor gespeichert, sodass ich von überall darauf zugreifen kann? Mach ich da einen Denkfehler?

    Struktur von der Funktion zurückgeben lassen oder noch besser einen Zeiger übergeben.

    struct FormProperties getColor(unsigned hex_color)
    {
    	struct FormProperties color;
    
    	// .... wie auch immer ...
    	return color;
    }
    
    void getColor ( struct FormProperties* pcolor, unsigned hex_color )
    {
    	pcolor->color_blue = ...
    	// .... wie auch immer ...
    	return;
    }
    


  • Weil die Variable lokal ist (Zeile 6)
    Nutze den Rückgabewert der Funktion.



  • DirkB schrieb:

    Weil die Variable lokal ist (Zeile 6)
    Nutze den Rückgabewert der Funktion.

    Stimmt zum Teil. Ich habe es in Zeile 6 unnötigerweise nochmal definiert.
    In Wirklichkeit habe ich die Variable "color" schon im struct ganz zu beginn des Programmes (natürlich außeralb der main) deklariert.

    struct FormProperties
    {
      //.....
    
    } ...,color, ...;
    

    Deswegen sollte es doch funktionieren hab ich mir gedacht.

    CJosef schrieb:

    GuitarKing schrieb:

    D.h. "x_r" ist die eingelesene Variable und die wird in "x" über "pos_x" in das struct gespeichert. Soweit so gut.

    Soweit so gut? Wozu der Umweg über eine Variable, warum nicht direkt in der Struktur speichern?

    Wie? Das Speichern eines Wertes in eine Strukt Variable funktioniert doch nur so oder?

    CJosef schrieb:

    GuitarKing schrieb:

    Nun habe ich eine andere Funktion (getColor), in der ich eine eingelesene hexadezimal codierte RGB Farbe (übergabe an "hex_color") mit 6 Stellen von der main Funktion aufteile, um die einzelnen Farbanteile herauszufischen (mit bitshifting etc.).

    Dafür brauchst du weder for Schleife noch if/else Anweisungen.

    unsigned hex_color = 0xAABBCCDD;
    	printf ( "%x %x %x %x\n", hex_color>>24, (hex_color>>16) & 0x00FF, (hex_color >> 8) & 0x00FF, hex_color & 0x00FF );
    

    Ich möchte ja die einzelnen Teile von "hex_color" in einzelne Farb Variablen speichern. So gebe ich sie ja nur aus.
    Wie gesagt, ich bin mehr oder weniger noch Anfänger 😉



  • GuitarKing schrieb:

    Deswegen sollte es doch funktionieren hab ich mir gedacht.

    Es wird in die lokale Variable geschrieben, die globale bleibt unberücksichtigt.

    CJosef schrieb:

    GuitarKing schrieb:

    D.h. "x_r" ist die eingelesene Variable und die wird in "x" über "pos_x" in das struct gespeichert. Soweit so gut.

    Soweit so gut? Wozu der Umweg über eine Variable, warum nicht direkt in der Struktur speichern?

    GuitarKing schrieb:

    Wie? Das Speichern eines Wertes in eine Strukt Variable funktioniert doch nur so oder?

    Wenn der Wert aus einer Datei kommt, kann er gleich in der Strukturvariable landen, ohne eine Zwischenvariable.

    GuitarKing schrieb:

    Ich möchte ja die einzelnen Teile von "hex_color" in einzelne Farb Variablen speichern. So gebe ich sie ja nur aus.
    Wie gesagt, ich bin mehr oder weniger noch Anfänger 😉

    Die Werte, die printf ausgibt kann man auch speichern

    unsigned farbwert8bit = (hex_color>>16) & 0x00FF;
    


  • Und wie speichere ich den wert dann in die Globale Variable?

    CJosef schrieb:

    GuitarKing schrieb:

    Wie? Das Speichern eines Wertes in eine Strukt Variable funktioniert doch nur so oder?

    Wenn der Wert aus einer Datei kommt, kann er gleich in der Strukturvariable landen, ohne eine Zwischenvariable.

    Also, ich möchte einfach meine eingescannten Farbanteile (in der extra Funktion) Global in mein "struct FormProperties" speichern, von dem aus dann die Variable weitergegeben und verarbeitet werden kann. Wie kann ich das realisieren?
    Kann sein, dass ich ein wenig auf der Leitung stehe. Allerdings sitze ich schon den ganzen Tag am Programm und versuche diverse Probleme zu lösen. Verzeiht mir 😉



  • Ganz einfach, entferne die lokale Variable color, damit die globale Variable color sichtbar wird.
    Und lies dir das Kapitel deines Lehrbuchs über die Sichtbarkeit von Variablen durch.



  • Kannst du interessehalber die Aufgabenstellung posten?



  • In deinem eigenen Interesse: Verzichte auf globale Variablen.
    Die machen meist nur Ärger.

    Du kannst deine Farbwerte auch gleich in die Variablen einlesen:

    char *farbe = "1144aa";
    int r,g,b;
    sscanf(farbe,"%2x%2x%2x",&r,&g,&b);
    


  • An alle schonmal danke für eure Hilfe!
    Ich bin jetzt zum Schluss gekommen, dass die Farbanteile doch nicht aufgeteilt werden müssen. Sie werden einfach gleich so wie sie daher kommen als unsigned int behandelt und weiter verarbeitet. Das macht die ganze Sache natürlich viel einfacher.
    Trotzdem hab ich wieder eine Frage 😉 Und zwar, gilt es, die verschiedenen ID der Formen, die eingelesen werden, auf ihre Existenz zu überprüfen. Also ob sie schon vorhanden sind oder nicht. Sobald eine oder mehrere IDs mehrfach vorommen, soll ein Fehler ausgegeben werden. Ich weiß, wie man Strings auf gewisse Zeichen etc. überprüfen kann, nur ist zu bedenken, dass das Ganze recht dynamisch sein muss, d.h. es können beliebig viele Formen und entsprechend beliebig viele IDs daher kommen. Also ich schätze mal, ich überprüf das am Besten in den Structs, da ja immer die selbe Reihenfolge Einlesen einer Zeile -> speichern in Struct -> übergabe an Weiterverarbeitung gilt. D.h. ich müsste die IDs irgendwie im Struct überprüfen, wenn sie hereinkommen. Oder? Wie mach' ich das am Besten?

    Zur Allgemeinen Aufgabenstellung:
    Eine Eingabedatei enthält eine textuelle Beschreibung des Bildes. Jede Zeile beschreibt dabei entweder ein Rechteck, einen Kreis oder ein Dreieck das vollständig mit der angegebenen Farbe ausgefüllt ist.Die Werte innerhalb der Anführungszeichen sind dabei beliebig wählbar, das restliche Format bleibt jedoch immer gleich. Es kann sogar die hier angegebene Reihenfolge der einzelnen Eigenschaften als gegeben vorausgesetzt werden.
    Die ID ist eine eindeutige vorzeichenlose 32bit Ganzzahl. Wenn sich zwei Objekte überschneiden, soll immer das Objekt mit der höheren ID das andere Objekt verdecken. Die Farbe wird als 6-stellige Hexadezimalzahl angegeben, wobei die ersten beiden Stellen den Rot-Anteil beschreiben, die beiden mittleren Stellen den Grün-Anteil und die letzten beiden Stellen den Blau-Anteil.
    Die Position des Objekts wird über eine ganzzahlige x und y Koordinate angegeben. Der Koordinatenursprung liegt in der linken oberen Ecke des Bildes. Die Koordinaten können auch negativ sein, die Werte für die Breite und Höhe des Rechtecks bzw. für den Radius des Kreises müssen jedoch positiv sein.

    Soweit das Wichtigste.

    Mfg


Anmelden zum Antworten