Seite 1 von 2

parsen von ASCII Dateien

Verfasst: Do Jul 14, 2011 7:40 am
von Bruno
Hallo!

Ich bin seit ca. 6 Wochen mit C unterwegs, was (auch Dank dieses Forums) gut klappt. Jetzt stehe ich aber vor folgendem Problem:

Ich möchte aus einer ASCII Date Werte lesen, wobei die Werte in Spalten ausgerichtet sind, d.h. der Wert steht z.B. in sen Spalten 1-8 oder 9-32 usw.

Da ich nicht davon ausgehen kann, daß alle Werte weniger als 8 Stellen haben oder alle Werte rechtsbündig stehen, komme ich mit strtok nicht weiter, da es sein kann, daß zwischen zwei Werten kein Leerzeichen vorkommt.

Was ich gerne programmieren würde, wäre eine Funktionread_int_from_line (s.u.), der ich die Zeile und die Spalten, aus denen ich die Werte lesen will (von - bis) gebe und den dort gelesenen Wert zurückbekomme:

while(!feof(file))
{
fgets(zeile,80,zeile);
von_spalte=1;
bis_spalte=11;
/* lesesn der Spalte 1 bis 11 und als int zurückgeben*/
wert_1=read_int_from_line( zeile, von_spalte, bis_spalte);}

Kann mir da jemand einen Tip geben wie man das am schlauesten macht?

Danke!

Re: parsen von ASCII Dateien

Verfasst: Do Jul 14, 2011 7:56 am
von Xin
Bruno hat geschrieben:Ich bin seit ca. 6 Wochen mit C unterwegs, was (auch Dank dieses Forums) gut klappt.
Dann erstmal ein sechs Wochen verspätetes Willkommen im Forum. ;-)
Bruno hat geschrieben:Ich möchte aus einer ASCII Date Werte lesen, wobei die Werte in Spalten ausgerichtet sind, d.h. der Wert steht z.B. in sen Spalten 1-8 oder 9-32 usw.

Da ich nicht davon ausgehen kann, daß alle Werte weniger als 8 Stellen haben oder alle Werte rechtsbündig stehen, komme ich mit strtok nicht weiter, da es sein kann, daß zwischen zwei Werten kein Leerzeichen vorkommt.

Was ich gerne programmieren würde, wäre eine Funktionread_int_from_line (s.u.), der ich die Zeile und die Spalten, aus denen ich die Werte lesen will (von - bis) gebe und den dort gelesenen Wert zurückbekomme:

wert_1=read_int_from_line( zeile, von_spalte, bis_spalte);}

Kann mir da jemand einen Tip geben wie man das am schlauesten macht?
Die Signatur wäre also

int read_int_from_line( char * zeile, unsigned int von_spalte, unsigned int bis_spalte );

An Deiner Stelle würde ich mir das Zeichen an zeile[ bis_spalte ] merken und dann mit einem Nullbyte überschreiben. Anschließend hast Du einen C-String, denn Du mit der Funktion atoi parsen kannst. Nach dem Parsen setzt Du das gemerkte Zeichen wieder zurück an seine Stelle. Damit hast Du Zeile nicht verändert und konntest Deine Zahl sauber auslesen.

Das ist ein recht merkwürdiges Format, das Du da hast, wie kommt's?

Re: parsen von ASCII Dateien

Verfasst: Do Jul 14, 2011 8:18 am
von cloidnerux
Willkommen im Forum

Deine Datei sieht mir stark nach einer CSV Datei aus. Hast du sie selber generiert?
Soweit ich weiß, ist es Üblich die einzelnen Spalten über ein Trennzeichen zu Trennen.

Ansonsten könntest du doch auch immer 8 stellen lesen, alles Unnötige entfernen und dann die zahl auslesen, wenn ich deine Beschreibung der Datei richtig verstanden habe.

MfG cloidnerux.

Re: parsen von ASCII Dateien

Verfasst: Do Jul 14, 2011 9:08 am
von Bruno
cloidnerux hat geschrieben:Willkommen im Forum

Deine Datei sieht mir stark nach einer CSV Datei aus. Hast du sie selber generiert?
Soweit ich weiß, ist es Üblich die einzelnen Spalten über ein Trennzeichen zu Trennen.

Ansonsten könntest du doch auch immer 8 stellen lesen, alles Unnötige entfernen und dann die zahl auslesen, wenn ich deine Beschreibung der Datei richtig verstanden habe.

MfG cloidnerux.
Hallo!

Leider keine CSV-Datei und generiert wird die Datei von verschiedenen Programmen, die den FEM Code NASTRAN rausschreiben.
Leider hat jeder Programmhersteller seine eigene Philosophie wie er mit dem 8-Spaltenformat, was NASTRAN verlangt umgeht.
Und spätenstens, wenn ich 8stellige IDs für Knoten oder Element vergeben muß bin ich mit strtok am Ende der Weisheit.

Ciao

Jürgen

Re: parsen von ASCII Dateien

Verfasst: Do Jul 14, 2011 9:32 am
von cloidnerux
Leider keine CSV-Datei und generiert wird die Datei von verschiedenen Programmen, die den FEM Code NASTRAN rausschreiben
Also etwas exotischeres, musste erstmal googlen was das ist^^
Leider hat jeder Programmhersteller seine eigene Philosophie wie er mit dem 8-Spaltenformat, was NASTRAN verlangt umgeht.
Also legt NASTRAN fest, wie die Datei aufgebaut sein soll und NASTRAN muss es ja auch Interpretieren können.
Soweit ich dich jetzt verstanden habe, gibt es 8 Spalten zu 8 Zeichen?
Und spätenstens, wenn ich 8stellige IDs für Knoten oder Element vergeben muß bin ich mit strtok am Ende der Weisheit.
Wieso nimmst du nicht was anderes als strtok, bzw Programmierst dir was eigenes?
Hast du dir mal die anderen string-Funktionen angeschaut und/oder das Prinzip hinter C-Strings verstanden?

Re: parsen von ASCII Dateien

Verfasst: Do Jul 14, 2011 9:39 am
von fat-lobyte
Xin hat geschrieben:An Deiner Stelle würde ich mir das Zeichen an zeile[ bis_spalte ] merken und dann mit einem Nullbyte überschreiben. Anschließend hast Du einen C-String, denn Du mit der Funktion atoi parsen kannst. Nach dem Parsen setzt Du das gemerkte Zeichen wieder zurück an seine Stelle. Damit hast Du Zeile nicht verändert und konntest Deine Zahl sauber auslesen.
cloidnerux hat geschrieben:Ansonsten könntest du doch auch immer 8 stellen lesen, alles Unnötige entfernen und dann die zahl auslesen, wenn ich deine Beschreibung der Datei richtig verstanden habe.
Bruno hat geschrieben:Und spätenstens, wenn ich 8stellige IDs für Knoten oder Element vergeben muß bin ich mit strtok am Ende der Weisheit.
Ein paar vorschläge hast du ja schon.
Hier noch einer von mir:

Leg dir ein 9 Byte array an, setz das 9. byte auf '\0'. Lies mit fread() immer 8 bytes ein, und parse deinen string mit atoi(). Sollte fread() einmal weniger als 8 Zeichen lesen weißt, du, dass du am Ende der Datei bist.

Wenn es vorkommt dass die Felder kürzer sind (z.B. am Ende der Zeile) musst dir noch was überlegen, aber ich bin mir sicher das schaffst du ;-)

Re: parsen von ASCII Dateien

Verfasst: Do Jul 14, 2011 4:45 pm
von Bruno
Hallo!

Habe fread mal im I-net gesucht und folgendes gefunden:

Angeblich werden damit 10 Blöcke a 1*sizeof(int) aus der Datei wert.dat gelesen.

Code: Alles auswählen

#include <stdio.h>
#include <stdlib.h>
int main(void) 
{
   int Buffer[10];
   FILE *Datei;
   int i;
   Datei = fopen("wert.dat", "r+b");
   if(Datei != NULL)
   {
      fread(&Buffer, 1*sizeof(int), 10, Datei);
   }
   for(i = 0; i < 10; i++)
   {
      printf("Wert %d = %d\n", i, Buffer[i]);
   }
 return EXIT_SUCCESS;
}
Mit der Datei wert.dat mit dem Inhalt "12345678901234567890" bekomme ich den Output:

Code: Alles auswählen

Wert 0 = 875770417
Wert 1 = 943142453
Wert 2 = 842084409
Wert 3 = 909456435
Wert 4 = 809056311
Wert 5 = 10
Wert 6 = 4195809
Wert 7 = 0
Wert 8 = 0
Wert 9 = 0
Was mich nicht wirklich glücklich macht...

Ich durchschaue aber nicht wo der Fehler liegt.

Edit by Xin: Code-Flags hinzugefügt.

Re: parsen von ASCII Dateien

Verfasst: Do Jul 14, 2011 5:06 pm
von fat-lobyte
Ich will dir ja den spaß nicht verderben, deswegen nur ein paar wenige Tips:
Kuck dir mal gaaannnzz genau an WAS du ausliest, wie groß das ist, wieviel du davon du ausliest und welches format das hat.
Dann Überleg dir was du auslesen willst, und wie es kodiert ist (ein blick in den Titel des Threads könnte helfen ;-) ), und wie du daraus das machst was du willst.

Re: parsen von ASCII Dateien

Verfasst: Do Jul 14, 2011 5:08 pm
von Xin
Das könnte ausführlicher werden. ^^

Also... erstens enthält die wert.dat keine ints, sondern eine Ansammlung von ASCII-Zeichen (char), die zufälligerweise Ziffern sind. Damit kann ein Computer eigentlich nichts anfangen, ASCII-Werte sind nur eine Konvention, wie Zahlen (das womit Computer etwas anfangen können) als Text dargestellt werden können (womit wir dann etwas anfangen können.)
Für den Computer ist die ASCII-Wert '0' der Integer-Wert 48, '1' ist 49 usw.
Ein char ist 1 Byte groß, ein int ist vier Byte groß.

Wenn Du nun vier Byte (je ein chars) hintereinander klemmst (also ein int), dann bekommst Du eine Zahl zwischen -2'000'000'000 und +2'000'000'000 raus, während als Text gerade mal vier Ziffern reinpassen. Beides ist 4 Byte groß, aber der Computer betrachtet diese Daten eben vollkommen anders - sie haben ja auch unterschiedliche Typen.

Du musst nicht 10 ints einlesen, sondern 10 chars (also ASCII-Zeichen), um "1234567890" in einem Buffer unterzubringen. Der Buffer sollte dann vom Typ 'char' sein:

Code: Alles auswählen

char Buffer[11];
Du brauchst 11 chars, damit Du hinten ein Nullbyte anfügen kannst:

Code: Alles auswählen

Buffer[10] = '\0';
10, weil der Index bei 0 beginnt und 10 somit das 11. Char ist.
Dann liest Du mit fread 10 Zeichen ein:

Code: Alles auswählen

fread(&Buffer, sizeof(char), 10, Datei);
Wenn das geklappt hat, kommen wir wieder zu meinem ersten Posting: Du kannst nun den Buffer an die Funktion atoi (sprechbar "AsciiToInteger") packen.

Code: Alles auswählen

int wert = atoi( Buffer );
Jetzt hast Du die erste Zahl gelesen und als als Typ "Integer" vorliegen, die Du mit printf und %d dann ausgeben kannst:

Code: Alles auswählen

printf( "Wert als String: %s\n", Buffer );
printf( "Wert as Integer: %d\n", wert );
In der Variable "wert" hast Du jetzt die gewünschte Zahl, so dass die Maschine etwas damit anfangen kann und Du damit Deine Berechnungen durchführen kannst.

Re: parsen von ASCII Dateien

Verfasst: Fr Jul 15, 2011 7:03 am
von Bruno
Hallo!

Danke fürs auführliche Posting!

Mann ist das kompliziert...

Ich denke immer noch in Fortran, da sind Strings ein eigener Datentyp und der Umgang damit ist recht simpel

Naja, 12 jahre Fortran gegen 6 Wochen C... ist klar, wer da verliert :-)))

Ciao

Jürgen