Strukturierte Datensätze flexibel einlesen



  • Hallo,

    ich möchte gerne eine Routine schreiben, mit deren Hilfe ich strukturierte Datensätze flexibel einlesen kann.

    Die Datensätze sind wie folgt organisiert:

    TITLE = "Beispieldatensatz"
    VARIABLES = "CoordinateX" "CoordinateY" "CoordinateZ"
    ZONE T = "Zone 1"
     I=2, J=2, K=1, ZONETYPE=Ordered
     DATAPACKING=POINT
    1 1 1000
    2 1 2000
    3 1 3000
    4 1 4000
    

    Wie man erkennen kann, sind die Daten spaltenweise organisiert. Demnach entspricht Spalte 1 = "CoordinateX", Spalte 2 = "CoordinateY" und so weiter.

    Ich plane folgende Vorgehensweise für die Routine readMyTecData:
    1. Prüfe, ob die gewünschten Datensätze vorhanden sind. Hierzu wird nur geprüft, ob die Variablennamen "CoordinateX", ... vorhanden sind.
    2. Lese die Indizes I, J, K ein
    3. Prüfe, wie die Daten organisiert sind (,was mit DataPacking=POINT eindeutig festgelegt ist)
    4. Lese die Daten ein und speichere diese in entsprechende Felder.

    Ich würde die Routine gerne so gestalten, dass es möglich ist unterschiedliche Formate einzulesen. Beispielsweise könnte der Datensatz auch wie folgt aussehen:

    TITLE = "Beispieldatensatz"
    VARIABLES = "StreamWise Position" "RTheta"
    ZONE T = "Zone 1"
     I=4, J=1, K=1, ZONETYPE=Ordered
     DATAPACKING=POINT
    1 1000
    2 2000
    3 3000
    4 4000
    

    Meine Frage:
    1. Ich wüsste gerne, wie man die Variablenübergabe bzw. das Einlesen der Daten gestaltet, so dass die Anzahl der Spalten flexibel ist. Ich mache mal einen Anfang. In dem Beispiel würde ich mit Varname1,...die Namen der Variablen übergeben, um diese in der Datei zu suchen. In *var1, *var2 sollen dann die Datensätze (Zahlen) geschrieben werden. Ist das so möglich? Ich habe keine Idee, wie das Zeilenlesen ablaufen sollte.

    #include <stdarg.h>
    
    int readTecData(FILE *fp, char *VarName1, char *VarName2,..., double *var1, *var2, ...) {
    	int retval = 0;
    
    	return retval;
    }
    

    2. Es ist möglich, dass die Zahlen nicht spaltenweise aber dafür blockweise abgelegt werden. Beispiel:

    1 1000 2 2000 3 3000 ...
    

    Analog in Spaltenorganisation:

    1 1000 
    2 2000 
    3 3000 ...
    

    Wie macht man dannn das Einlesen?

    Besten Dank im Voraus



  • Ich würde die Ein Inifile nahelegen... Ich habe bis jetzt nur gute Erfahrungen gesammelt. Die Daten kannst du dann direkt in eine Structur übertragen.
    Gruss Binggi



  • Erstmal würde ich eine Struktur für deine Zieldaten definieren.
    Dann ein Array bzw. eine dynamisch wachsende Liste darauf.
    Dann würde ich mal deine Formatangaben "I=2,J=2,K=2" usw. in ein einfacher auswertbares Format bringen, analog zu obigen also z.B.
    "FORMAT=I:1,J:2,K:3" o.ä. statt < I=2, J=2, K=1, ZONETYPE=Ordered>
    das "DATAPACKING=POINT" habe ich nicht verstanden
    Zeilenblock oder Einzelzeile müsstest du auch noch irgendwo definieren

    stdarg würde ich nicht empfehlen, besser ein Array mit Formatinfos für jede Spalte



  • Möglicherweise wäre Boost spirit oder Parsnip für dich interessant. Möglicherweise auch Reguläre Ausdrücke, falls du die noch nicht kennst.



  • Mir würde ein Beispiel sehr helfen, welches erklärt, wie ich mit fscanf(...) die einzelnen Elemente in einer Zeile parse und anschließend in die n-Vektoren hineinschiebe. Wenn das überhaupt geht!?!?

    Ich habe derartige Daten bislang immer formatiert eingelesen - aber wie bereits zuvor gesagt - ich habe keinen Plan, ob das jetzt noch möglich ist.!?!?



  • Ich versuche es noch einmal anders zu erklären, was mein Problem ist. Mit dem unten dargestellten Beispiel kann ich n Strings an die Funktion readHeader übergeben.

    #include <stdarg.h>
    
    int readHeader(char *filename, char *VARName1, char *VARName2, ...) {
    	FILE *fp;
    	int retval = 0;
    	int flag = 0;
    
    	if ((fp = fopen(filename, "r")) != NULL) {
    		do {
    		} while ((!feof(fp)) && (flag == 0));
    	} else {
    		sendInfoMsg("bsp.c", "readHeader", "Unable to open file \"%s\".\n", filename);
    	}
    	return retval;
    }
    

    Mein erster Gedanke war, an eine Funktion n-Pointer vom Typ double zu übergeben und diese mit der Funktionalität von fscanf zu kombinieren. Das Problem ist, dass fscanf (soweit mir bekannt ist) die Namen der Variablen explizit auflistet

    fscanf(fp, "%f%f%f", &zahl1, &zahl2, &zahl3)
    

    . Und das ist in meinem Fall nicht so, da ich zwischen 2 und 20 Variablen= Spalten einlesen können möchte.



  • Suchst du vielleicht die Funktion man: vfscanf?



  • Hallo,

    vielleicht bin ich zu doof aber ich verstehe noch nicht wie das genau funktionieren kann/soll.

    #include <stdarg.h>
    
    int  readTecData(FILE *fp, double *var1, ...)
    

    Die Funktion, welche ich oben definiert habe, besitzt eine variable Argumentenliste. Mit anderen Worten sollte es mir frei stehen, ob ich die Funktion readTecData so

    retval =  readTecData(*fileptr, &feld1, &feld2, &feld3)
    

    oder so

    retval =  readTecData(*fileptr, &feld1, &feld2, &feld3, &feld4)
    

    aufrufe. Ich kann mir aber nicht vorstellen, wie man an die Einlesefunktion "vscanf" eine variable Liste von Zeigern auf feld1, feld2, ... übergibt. Ich hoffe, ich mache mich klar....



  • mach doch 2 arrrays. eins mit den vorhandenen spalten und eins mit denen, die gesucht werden sollen.
    die anzahl der suchvorgänge reduzierst du mit binärer suche oder hashtable.



  • Phil270307 schrieb:

    Die Funktion, welche ich oben definiert habe, besitzt eine variable Argumentenliste. Mit anderen Worten sollte es mir frei stehen, ob ich die Funktion readTecData so

    retval =  readTecData(*fileptr, &feld1, &feld2, &feld3)
    

    oder so

    retval =  readTecData(*fileptr, &feld1, &feld2, &feld3, &feld4)
    

    aufrufe. Ich kann mir aber nicht vorstellen, wie man an die Einlesefunktion "vscanf" eine variable Liste von Zeigern auf feld1, feld2, ... übergibt.

    Du kannst schon darauf vertrauen, dass <stdarg.h> funktioniert, auch wenn du dir dass nicht vorstellen kannst. Nur kann ich nicht erkennen, was an deinem o.g. Beispiel flexibel sein soll, wenn du für jeden deiner Anwendungsfälle eine KONSTANTE Anzahl vor Parametern übergeben musst. IMHO passt dein ganzer Ansatz nicht zu deiner Überschrift. Ich würde empfehle zu Beginn mit einfach strukturierten, blockweise in einer Zeile zusammenhängenden Daten für 1 Datensatz, anzufangen und dann mittels topdown (und nicht gleich zu Beginn über Implementierungsdetails nachzudenken (bottomup)). Beide Verfahren haben ihre Vorteile, ich glaube für diesen Fall wäre topdown besser. Also z.B.

    #define MAXWERTE 100
    typedef struct {
    int wert[MAXWERTE];
    } Daten;
    
    typedef struct {
    int anzahlwerte;
    ...
    } Konfiguration;
    
    #define MAXDS 1000
    #define ZEILEGROESSE 1000
    Daten datensatz[MAXDS];
    int i=0;
    char zeile[ZEILEGROESSE];
    ...
    Konfiguration k={3,...};
    while( fgets(zeile,ZEILEGROESSE,file) )
      if( verarbeiteDatensatz(zeile,datensatz[i],k) )
        ++i;
    
    int verarbeiteDatensatz(char *z,Daten d,Konfiguration k)
    {
      char *t;
      int i=0;
      for( t=strtok(z," ");t && i<k.anzahlwerte;t=strtok(0," "),++i ) {
    /* oder was auch immer du als Trennzeichen hast; va_arg nützt hier nichts,
    du müsstest dann hier den Formatstring entsprechend aufbereiten und auch die
    Anzahl Werte hier konkret als Parameter in der vsscanf-Liste angeben,
    das wäre NICHT flexibel */
      d.wert[i]=atoi(t);
      ...
      }
      return i==k.anzahlwerte;
    }
    


  • Könntest Du mir bitte einmal ein Beispiel geben, welches konkret das Einlesen aus der Datei beinhaltet. Danke.



  • Phil270307 schrieb:

    vielleicht bin ich zu doof aber ich verstehe noch nicht wie das genau funktionieren kann/soll.

    Was hast du denn bis jetzt getan, um dich darüber zu informieren?

    Google: example vprintf
    Google: example vscanf


Anmelden zum Antworten