簡體   English   中英

CSV文件高級解析

[英]CSV file advanced parsing

我在解析.csv文件時遇到問題。 我有一個這樣定義的struct world

typedef struct world
{
    char worldName[30];
    int worldId;
    char *message;
    char **constellationArray;
    struct world *next;
} tWorld;

我有一個.csv文件,其設計如下(因此,“ c”是“分號”的意思):

worldId;worldName;message;constellationArray
1;K'tau;Planeta pod ochranou Freyra;Aquarius;Crater;Orion;Sagittarius;Cetus;Gemini;Earth
2;Martin's homeworld;Znicena;Aries;Sagittarius;Monoceros;Serpens;Caput;Scutum;Hydra;Earth
3;...

任務似乎很簡單:編寫一個方法loadWorlds(char *file) 加載文件並解析它。 不能保證星座數量。 每條新線表示一個新世界,我必須創建這些世界的鏈接列表。 我對此有一個大概的想法,但我無法使其正常工作。 我有一個稱為tWorld *createWorld() ,它的實現方式如下:

tWorld *createWorld() {
    tWorld *world;
    world = (*tWorld)malloc((sizeof(tWorld)));
    return world;
}

我必須在我的loadWorlds(char * file)中使用此方法。 另外,我必須使用以下命令將它們序列化為鏈接列表:

if (*lastWorld == NULL){
    *lastWorld = nextWorld;
}else{
    (*actualWorld)->next = nextWorld;
}
*actualWorld = nextWorld;

但是我不知道什么時候使用它。 這是我的loadWorlds(char *file)草圖:

void loadWorlds(char *file)
{
    FILE *f;
    char text[30];
    char letter;
    tWorld *lastWorld = NULL, *actualWorld = NULL, *world;

    //f = fopen(file, "r");

    if(!(f = fopen(file, "r")))
    {
        printf("File does not exist! \n");
        while(!kbhit());
    }
    else
    {
        while(!(feof(f)) && (letter = fgetc(f))!= '\n')
        {

            if((znak = fgetc(f)) != ';')
            {

            }

        }
    }
}

我將不勝感激任何想法使這項工作。

從總體上考慮, “如何解析此文件?...(此外,我必須將它們序列化到鏈接列表中)”這個問題是不平凡的。 您的“我如何解析此文件?” 它本身就是一個問題。 關於鏈表的第二部分是一個完全獨立的問題,盡管您似乎是指單鏈表,但根本沒有充分解釋。 酒的標簽有很多不同的處理方法。 我將嘗試提供一種方法來幫助您。

在下面的例子,而不是創建一個單一的靜態字符數組worldName一個內tWorld其中所有其他字符串是動態分配的結構,我已經改變worldName到一個character pointer ,以及。 如果必須使用static array of charsstatic array of chars ,可以很容易地對其進行更改,但是只要分配剩余的字符串,也可以為worldName分配worldName

至於問題的parsing部分,您可以使用注釋中標識的任意數量的庫函數,也可以簡單地使用幾個pointers並根據需要逐步完成每一行來解析每個字符串。 兩種方法都可以。 使用簡單指針的唯一好處(除了學習方面)是避免重復的函數調用,在某些情況下,重復調用可能會更有效率。 從動態分配的行中解析數據時,有一個注意事項確保保留緩沖區的起始地址,以確保可以正確跟蹤和釋放分配的內存。 一些庫函數會破壞原始緩沖區(例如strtok等),如果您通過緩沖區本身而不以某種方式保留原始起始地址,則可能導致有趣的錯誤。

下面的函數read_list_csv使用一對字符指針來解析從csv文件讀取的每一行(實際上是semi-colon separated值)到tWorld結構的每個成員中,以解析輸入行。 然后read_list_csv調用ins_node_end將每個已填充和分配的ins_node_end tWorld nodes插入到singularly-linked circular linked-list 對解析進行了注釋,以幫助解釋邏輯,但總而言之,它只是將起始指針p設置為開頭,然后使用結束指針ep檢查行中的每個字符,直到分號; 找到后,暫時設置; \\0 (nul)並讀取p指向的字符串。 臨時\\n被替換為原來的; 然后從下一個字符開始重復該過程,直到該行被完全解析為止。

您的問題linked-list部分涉及更多。 許多linked-list examples僅得到部分解釋並且通常等效,這使情況變得復雜。 此外,除非您可以添加linked-list ,從linked-list讀取,從linked-list刪除,並且擺脫linked-list而不會像篩子那樣泄漏內存,否則linked-list幾乎沒有用。 當您查看示例時,請注意鏈接列表有兩種主要形式。 HEAD/TAIL列表或circular列表。 兩者都可以singularly鏈接或doubly鏈接。 HEAD/TAIL列表通常將單獨的指針用於列表開頭或HEAD與列表結尾或TAIL節點(通常設置為NULL )。 circular列表只是使結束節點的next指針指向列表的開頭。 兩者都有其用途。 circular列表的主要好處是,無論您從列表的何處開始,都可以將列表任何節點遍歷任何其他節點。 (由於沒有end-node ,因此您可以從任何節點開始遍歷所有節點)。

下面的示例是一個singularly linked circular list 它提供以下功能:創建節點,將其插入列表,對節點計數,打印整個列表,從列表中刪除節點以及刪除列表。 重要的是,它釋放了分配給列表的所有內存。

通過示例的parsing部分和示例的linked-list部分,讓我知道您是否有疑問。 雖然列表實現應該相當可靠,但是可能存在一些未發現的問題。 代碼后顯示了用於測試的數據文件以及示例輸出。 代碼期望數據文件作為第一個參數,而可選的(從零開始)節點將作為第二個參數刪除(默認值:節點2):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXL 256
// #define wName 30

typedef struct world
{
    // char worldName[wName];
    char *worldName;
    int worldId;
    char *message;
    char **constellationArray;
    struct world *next;
} tWorld;

/* allocate & populate node */
tWorld *create_node (int wid, char *wnm, char *msg, char **ca);

/* insert node into list */
tWorld *ins_node_end (tWorld **list, int wid, char *wnm, char *msg, char **ca);

/* read data from file fname and add to list */
tWorld *read_list_csv (tWorld **list, char *fname);

/* return the number of nodes in list */
size_t getszlist (tWorld *list);

/* print all nodes in list */
void print_list (tWorld *list);

/* free memory allocated to tWorld list node */
void free_node (tWorld *node);

/* (zero-based) delete of nth node */
void delete_node (tWorld **list, int nth);

/* delete tWorld list & free allocated memory */
void delete_list (tWorld *list);

int main (int argc, char **argv)
{
    if (argc < 2) {
        fprintf (stderr, "error: insufficient input. Usage: %s <filename> [del_row]\n", argv[0]);
        return 1;
    }

    char *fname = argv[1];
    tWorld *myworld = NULL;             /* create pointer to struct world   */

    read_list_csv (&myworld, fname);    /* read fname and fill linked list  */

    printf ("\n Read '%zd' records from file: %s\n\n", getszlist (myworld), fname);

    print_list (myworld);               /* simple routine to print list     */

    int nth = (argc > 2) ? atoi (argv[2]) : 2;
    printf ("\n Deleting node: %d\n\n", nth);
    delete_node (&myworld, nth);        /* delete a node from the list      */

    print_list (myworld);               /* simple routine to print list     */

    delete_list (myworld);              /* free memory allocated to list    */

    return 0;
}

/* allocate & populate node */
tWorld *create_node (int wid, char *wnm, char *msg, char **ca) 
{
    tWorld *node = NULL;

    node = malloc (sizeof *node);
    if (!node) return NULL;

    node-> worldId = wid;
    node-> worldName = wnm;
    node-> message = msg;
    node-> constellationArray = ca;

    return node;
}

/* insert node into list */
tWorld *ins_node_end (tWorld **list, int wid, char *wnm, char *msg, char **ca) 
{
    tWorld *node = NULL;
    if (!(node = create_node (wid, wnm, msg, ca))) return NULL;


    if (!*list) {    /* if empty, create first node */
        node-> next = node;
        *list = node;
    } else {         /* insert as new end node */
        if (*list == (*list)-> next) { /* second node, no need to iterate */
            (*list)-> next = node; 
        }
        else                           /* iterate to end node & insert    */
        {
            tWorld *iter = *list;      /* second copy to iterate list     */
            for (; iter->next != *list; iter = iter->next) ;
            iter-> next = node;        /* insert node at end of list      */
        }
        node-> next = *list;           /* set next pointer to list start  */
    }

    return *list;   /* provides return as confirmation  */
}

/* read list from file fname and add to list */
tWorld *read_list_csv (tWorld **list, char *fname)
{
    FILE *fp = fopen (fname, "r");
    if (!fp) {
        fprintf (stderr, "%s() error: file open failed for '%s'\n", __func__, fname);
        return NULL;
    }

    /* allocate and initialize all variables */
    char *line = calloc (MAXL, sizeof *line);
    char *p = NULL;
    char *ep = NULL;
    char *wnm = NULL;
    int wid = 0;
    int lcnt = 0;
    char *msg = NULL; 
    char **ca = NULL;
    size_t idx = 0;

    while (fgets (line, MAXL, fp))      /* for each line in file    */
    {
        if (lcnt++ == 0) continue;      /* skip header row          */

        p = line;
        idx = 0;
        ep = p;
        size_t len = strlen (line);     /* get line length          */
        if (line[len-1] == '\n')        /* strip newline from end   */
            line[--len] = 0;

        while (*ep != ';') ep++;        /* parse worldId            */
        *ep = 0;
        wid = atoi (p);
        *ep++ = ';';
        p = ep;

        while (*ep != ';') ep++;        /* parse worldName          */
        *ep = 0;
        wnm = strdup (p);
        *ep++ = ';';
        p = ep;

        while (*ep != ';') ep++;        /* parse message            */
        *ep = 0;
        msg = strdup (p);
        *ep++ = ';';
        p = ep;

        ca = calloc (MAXL, sizeof *ca); /* allocate constellationArray */
        if (!ca) {
            fprintf (stderr, "%s() error allocation failed for 'ca'.\n", __func__);
            return NULL;
        }
        while (*ep)                     /* parse ca array elements  */
        {
            if (*ep == ';')
            {
                *ep = 0;
                ca[idx++] = strdup (p);
                *ep = ';';
                p = ep + 1;
                /* if (idx == MAXL) reallocate ca */
            } 
            ep++;
        }
        if (*p) ca[idx++] = strdup (p); /* add last element in line */

        ins_node_end (list, wid, wnm, msg, ca); /* add to list      */
    }

    /* close file & free line */
    if (fp) fclose (fp);
    if (line) free (line);

    return *list;
}

/* return the number of nodes in list */
size_t getszlist (tWorld *list) {

    const tWorld *iter = list;  /* pointer to iterate list  */
    register int cnt = 0;

    if (iter ==  NULL) {
        fprintf (stdout,"%s(), The list is empty\n",__func__);
        return 0;
    }

    for (; iter; iter = (iter->next != list ? iter->next : NULL)) {
        cnt++;
    }
    return cnt;
}

/* print all nodes in list */
void print_list (tWorld *list) {

    const tWorld *iter = list;  /* pointer to iterate list  */
    register int idx = 0;
    char *stub = " ";

    if (iter ==  NULL) {
        fprintf (stdout,"%s(), The list is empty\n",__func__);
        return;
    }

    for (; iter; iter = (iter->next != list ? iter->next : NULL)) {
        printf (" %2d  %-20s  %-20s\n", 
                iter-> worldId, iter-> worldName, iter-> message);
        idx = 0;
        while ((iter-> constellationArray)[idx])
            printf ("%38s %s\n", stub, (iter-> constellationArray)[idx++]);
    }
}

/* free memory allocated to tWorld list node */
void free_node (tWorld *node)
{
    if (!node) return;

    register int i = 0;

    if (node-> worldName) free (node-> worldName);
    if (node-> message) free (node-> message);
    while (node-> constellationArray[i])
        free (node-> constellationArray[i++]);
    if (node-> constellationArray)
        free (node-> constellationArray);

    free (node);
}

/* (zero-based) delete of nth node */
void delete_node (tWorld **list, int nth)
{
    /* test that list exists */
    if (!*list) {
        fprintf (stdout,"%s(), The list is empty\n",__func__);
        return;
    }

    /* get list size */
    int szlist = getszlist (*list);

    /* validate node to delete */
    if (nth >= szlist || nth < 0) {
        fprintf (stderr, "%s(), error: delete out of range (%d). allowed: (0 <= nth <= %d)\n", 
                __func__, nth, szlist-1);
        return;
    }

    /* create node pointers */
    tWorld *victim = *list;
    tWorld *prior = victim;

    /* if nth 0, prior is last, otherwise node before victim */
    if (nth == 0) {
        for (; prior->next != *list; prior = prior->next) ;
    } else {
        while (nth-- && victim-> next != *list) {
            prior = victim;
            victim = victim-> next;
        }
    }

    /* non-self-reference node, rewire next */
    if (victim != victim->next) {
        prior-> next = victim-> next;

        /* if deleting node 0, change list pointer address */
        if (victim == *list)
            *list = victim->next;
    } else {  /* if self-referenced, last node, delete list */
        *list = NULL;
    }

    free_node (victim);  /* free memory associated with node */
}

/* delete tWorld list */
void delete_list (tWorld *list)
{
    if (!list) return;

    tWorld *iter = list;  /* pointer to iterate list  */

    for (; iter; iter = (iter->next != list ? iter->next : NULL))
        if (iter) free_node (iter);
}

輸入測試數據文件:

$ cat dat/struct.csv

worldId;worldName;message;constellationArray
1;K'tau;Planeta pod ochranou Freyra;Aquarius;Crater;Orion;Sagittarius;Cetus;Gemini;Earth
2;Martin's homeworld;Znicena;Aries;Sagittarius;Monoceros;Serpens;Caput;Scutum;Hydra;Earth
3;Martin's homeworld2;Znicena2;Aries2;Sagittarius2;Monoceros2;Serpens2;Caput2;Scutum2;Hydra2;Earth2
4;Martin's homeworld3;Znicena3;Aries3;Sagittarius3;Monoceros3;Serpens3;Caput3;Scutum3;Hydra3;Earth3

輸出:

$ ./bin/struct_ll_csv dat/struct.csv 1


 Read '4' records from file: dat/struct.csv

  1  K'tau                 Planeta pod ochranou Freyra
                                       Aquarius
                                       Crater
                                       Orion
                                       Sagittarius
                                       Cetus
                                       Gemini
                                       Earth
  2  Martin's homeworld    Znicena
                                       Aries
                                       Sagittarius
                                       Monoceros
                                       Serpens
                                       Caput
                                       Scutum
                                       Hydra
                                       Earth
  3  Martin's homeworld2   Znicena2
                                       Aries2
                                       Sagittarius2
                                       Monoceros2
                                       Serpens2
                                       Caput2
                                       Scutum2
                                       Hydra2
                                       Earth2
  4  Martin's homeworld3   Znicena3
                                       Aries3
                                       Sagittarius3
                                       Monoceros3
                                       Serpens3
                                       Caput3
                                       Scutum3
                                       Hydra3
                                       Earth3

 Deleting node: 1

  1  K'tau                 Planeta pod ochranou Freyra
                                       Aquarius
                                       Crater
                                       Orion
                                       Sagittarius
                                       Cetus
                                       Gemini
                                       Earth
  3  Martin's homeworld2   Znicena2
                                       Aries2
                                       Sagittarius2
                                       Monoceros2
                                       Serpens2
                                       Caput2
                                       Scutum2
                                       Hydra2
                                       Earth2
  4  Martin's homeworld3   Znicena3
                                       Aries3
                                       Sagittarius3
                                       Monoceros3
                                       Serpens3
                                       Caput3
                                       Scutum3
                                       Hydra3
                                       Earth3

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM