CSV Kopfzeilenloop



  • Und wenn ich jetzt bei Straße eintrage:
    Hauptstraße 54, Haus 3
    dann ist auf einmal alles kaputt 🙂

    Ich hoffe, dass du das nur eine Lernaufgabe ist und kein reales Problem?



  • @wob Ist nur eine Lernaufgabe, darfst aber gerne elaborieren. Ich nehme alle informationen mit die ich bekommen kann.



  • @Reche
    Das Problem tritt auf, wenn das Trennzeichen selbst Bestandteil der Daten ist, dann darf es nicht als Trennzeichen behandelt werden. Üblicherweise benutzt man dann Escape-Sequenzen, um das zu kennzeichnen, dann brauchst du aber eigene Tokenizer-Funktion, da nicht jedes Trennzeichen-Zeichen als Trennzeichen behandelt werden darf. Bei CSV-Dateien ist es auch üblich, einzelne Daten in Hochkommata einzufassen, und alles innerhalb der Hochkommata als Daten zu verwenden.

    Beispiel:

    // Fehler, "Hauptstraße 54, Haus 3" ist ein Token und gehört zusammen
    Max Mustermann, Hauptstraße 54, Haus 3, 12321, 0123/4567 
    
    // Eine Lösung, Daten werden spaltenweise in Hochkommata eingefasst, Parsen ist schwieriger
    "Max Mustermann", "Hauptstraße 54, Haus 3", "12321", "0123/4567" 
    
    // andere Lösung, Trennzeichen wird mit \ eingeleitet und darf nicht wie ein Trennzeichen behandelt werden
    Max Mustermann, Hauptstraße 54\, Haus 3, 12321, 0123/4567 
    

  • Mod

    @DocShoe sagte in CSV Kopfzeilenloop:

    Max Mustermann, Haupstraße 54

    Weitere Verkomplizierung: Ist das da nun die "Hauptstraße" oder die " Hauptstraße"?



  • @SeppJ sagte in CSV Kopfzeilenloop:

    @DocShoe sagte in CSV Kopfzeilenloop:

    Max Mustermann, Haupstraße 54

    Weitere Verkomplizierung: Ist das da nun die "Hauptstraße" oder die " Hauptstraße"?

    Keine Ahnung, wovon du redest 😉

    Edit:
    Lol, hatte da nochn Rechtschreibfehler drin, ich dachte, du spielst auf den an. Iwo stand da auch mal "Haupstraße". Aber ´ne trim() Funktion ist doch trivial.



  • @DocShoe Verstehe, das macht das ganze natürlich noch komplizierter und anfälliger, da muss ich wohl noch einige Fehler abfangen.
    @SeppJ Ja, Whitespaces sind auch immer so eine Sache 🙂



  • @DocShoe sagte in CSV Kopfzeilenloop:

    Aber ´ne trim() Funktion ist doch trivial.

    Schon, aber es könnte auch sein, dass man nicht trimmen darf, weil führende Leerzeichen eine Bedeutung haben könnten (bestes Beispiel: der Formatstring in scanf) - gut, bei Adressen ist das kein Problem.

    In der Praxis habe ich es oft mit csv-Dateien zu tun, die entweder Trennzeichen auch im Text nutzen oder zwar mit "..." quoten, wo dann aber doch alle paar tausend Zeilen auch mal " in den Daten vorkommt (ohne Sondermarkierung). Und dann beschwert man sich beim Kunden und der nimmt einfach Tab statt Komma - nur damit ich dann feststelle, dass irgendein Freitextfeld im csv auch Tabs enthalten kann (und das auch vorkommt). Daher: csv selbst machen geht fast immer irgendwie schief.


  • Gesperrt

    Hier mal das Parsen nur der Kopfzeile (ansi-c, pedantisch):

    #define _GNU_SOURCE
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define COLS 5
    
    char header[COLS][100];
    
    int readHeader(char *fn)
    {
        FILE *fp;
        char *line = NULL;
        size_t len = 0;
        ssize_t read;
        char *ptr = NULL;
        size_t i = 0;
        int ret = 1;
    
        fp = fopen(fn, "r");
        if (fp == NULL)
        {
            ret = 0;
            return ret;
        }
    
        read = getline(&line, &len, fp);
        if (read != -1)
        {
            ptr = strtok(line, ",");
            while (i < COLS && ptr != NULL && strlen(ptr) < 100)
            {
                printf(" found:%s\n", ptr);
                strcpy(header[i], ptr);
                ptr = strtok(NULL, ",");
                i++;
            }
            if (i != COLS || ptr != NULL)
            {
                ret = 0;
            }
        }
        else
        {
            ret = 0;
        }
    
        fclose(fp);
        if (line)
        {
            free(line);
        }
    
        return ret;
    }
    
    int main(void)
    {
        size_t i = 0;
    
        if (readHeader("mycsv.txt"))
        {
            while (i < COLS)
            {
                printf("%s\n", header[i++]);
            }
        }
    
        exit(EXIT_SUCCESS);
    }
    

    Geholfen hat mir dabei: https://www.c-howto.de/tutorial/strings-zeichenketten/string-funktionen/string-zerteilen/

    Jetzt brauchst du nur noch eine Parse-Funktion für den Tabellenkörper. Die ist eigentlich ähnlich.


  • Gesperrt

    Wieso sagt keiner mehr was? Das lässt ja fast den Verdacht zu, dass alles richtig wäre ...



  • @TaucherOne
    ssize_t ist kein ANSI C
    getline ist kein ANSI C
    &line ist UB
    strtok benutzt man nicht sondern fgets+sscanf
    u.v.a.m.


  • Mod

    Damit das allen klar ist: TaucherOne ist die neueste Inkarnation unseres ansässigen Trolls. Daher folgt in dem Beitrag auf "ansi-c, pedantisch" direkt als erstes #define _GNU_SOURCE (Das ist meiner Meinung nach sogar ein schöner Touch. Echte Qualitätstrollerei. Darauf muss man erst einmal kommen). Der will keine echte Kritik, sondern nur Aufmerksamkeit.


  • Gesperrt

    @Wutz Kritik zu äußern, ist das eine. Alternativen zu bilden, das andere. Oder anders: Welchen Mehrwert hat der TO von deinem Beitrag jetzt? 😉

    Du willst auf getline verzichten? Dann wünsche ich auf jeden Fall viel Erfolg dabei.



  • @TaucherOne
    Hat er doch geschrieben, zB fgets statt getline. Der Hinweis auf Undefined Behaviour eines Codeschnipsel hat gewaltigen Mehrwert. Finde ich zumindest. Muss halt jeder selbst entscheiden, ob er damit leben kann, dass ihm seine Anwendung jederzeit um die Ohren fliegen kann.


  • Gesperrt

    @DocShoe sagte in CSV Kopfzeilenloop:

    Der Hinweis auf Undefined Behaviour eines Codeschnipsel hat gewaltigen Mehrwert.

    Wenn das zutreffen würde (UB), wäre ich ganz bei dir.