簡體   English   中英

需要幫助從.csv文件C解析數據

[英]Need help parsing data from .csv file C

我有以下.csv文件,其中包含有關歌曲、藝術家、發行年份(如果指定)和收聽次數的信息:

Look What The Cat Dragged In,Poison,,Look What The Cat Dragged In by Poison,1,0,1,0
Nothin' But A Good Time,Poison,1988,Nothin' But A Good Time by Poison,1,1,21,21
Something To Believe In,Poison,1990,Something To Believe In by Poison,1,1,1,1
Talk Dirty To Me,Poison,1978,Talk Dirty To Me by Poison,1,1,1,1
A Salty Dog,Procol Harum,1969,A Salty Dog by Procol Harum,1,1,1,1
A Whiter Shade of Pale,Procol Harum,1967,A Whiter Shade of Pale by Procol Harum,1,1,3,3
Blurry,Puddle of Mudd,2001,Blurry by Puddle of Mudd,1,1,1,1
Amie,Pure Prairie League,,Amie by Pure Prairie League,1,0,4,0
Another One Bites the Dust,Queen,1980,Another One Bites the Dust by Queen,1,1,102,102
Bicycle Race,Queen,1978,Bicycle Race by Queen,1,1,3,3
Kiss You All Over,Kiss,1978,Kiss You All Over by Kiss,1,1,5,5

文件名和所需年份應作為命令行 arguments 給出,程序應打印該特定年份的所有歌曲。

例如: ./a.out music.csv 1978

Output:

Talk dirty to me
Bicycle Race
Kiss You All Over

代碼:

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

#define MAX 300

typedef struct {
    char song[101], *artist, *line;
    long int year;
} music;

int checkYear(char *word)
{
    for (int i = 0; i < strlen(word); i++) {
        if (!isdigit(word[i]))
            return 0;
    }
    return 1;
}

int main(int argc, char **argv)
{
    FILE *fin = fopen(argv[1], "r");
    if (!fin)
    {
        printf("Error opening the file.\n");
        return 1;
    }
    char buf[MAX];
    //int nLines = 0; //count the number of lines
    //music *array = NULL;
    while( fgets(buf, MAX, fin))
    {
        buf[strcspn(buf, "\n")] = '\0';  // strip the trailing newline
        char *word = strtok(buf, ",");
        while (word)
        {
            //printf("Word is : %s\n", word);
            if (checkYear(word))
            {
                //printf("Year : %s\n", word);
                music *array = (music *)malloc(sizeof(music));
                char *p;
                array->year = strtol(word, &p, 10);
                if (array->year == atoi(argv[2]))
                {
                    //printf("Year : %ld\t%d\n", array->year, atoi(argv[2]));
                    if (scanf("%100[^,]", array->song) == 1)
                    {
                        printf("Song : %s\n", array->song);
                    }
                }
            }
            word = strtok(NULL, ",");
        }
    }
    //printf("I've read %d lines\n", nLines);
    fclose(fin);
    return 0;
}

到目前為止,一切順利,我可以從每一行中提取指定的年份,但現在我只需要從這些行中打印出歌曲的名稱(行上的第一個標記)。 我考慮過使用scanf("%[^,]")來讀取和打印所有內容,直到第一個逗號,但它只是陷入了無限循環。 你能給我一個想法嗎? 提前致謝!

代碼中存在多個問題:

  • 您沒有檢查是否在命令行上傳遞了足夠的 arguments,否則可能會調用未定義的行為。
  • 您不需要分配music結構:您可以只解析前 3 個字段,直接檢查年份和 output 歌曲的名稱。
  • strtok()不適合從csv文件中拆分字段,因為它將分隔符序列視為單個分隔符,這是不正確的,並且如果某些字段為空,則會導致解析無效。
  • sscanf("%[^,]", ...)將無法轉換空字段。

要從csv行拆分字段,我建議您使用一個實用程序 function,它的行為類似於strtok_r()但為csv行量身定制。 一個簡單的版本將在,\n上停止並用 null 字節替換它們,返回初始指針並更新下一個字段的指針。 更高級的版本也可以處理引號。

這是修改后的版本:

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

#define MAX 300

char *get_field(char **pp) {
    char *p, *start;
    for (p = start = *pp; *p; p++) {
        if (*p == ',' || *p == '\n') {
            *p++ = '\0';
            break;
        }
    }
    *pp = p;
    return start;
}
     
int main(int argc, char *argv[]) {
    char buf[MAX];
    FILE *fin;
    char *filename;
    char *select_year;

    if (argc < 3) {
        printf("Missing arguments\n");
        return 1;
    }
    filename = argv[1];
    select_year = argv[2];
    fin = fopen(filename, "r");
    if (!fin) {
        printf("Error opening the file %s.\n", filename);
        return 1;
    }

    while (fgets(buf, sizeof buf, fin)) {
        char *p = buf;
        char *song = get_field(&p);
        char *artist = get_field(&p);
        char *year = get_field(&p);
        if (!strcmp(year, target_year)) {
            printf("%s\n", song);
        }
    }
    fclose(fin);
    return 0;
}

關於: scanf("%[^,]")這會消耗(最多但不包括)逗號。

所以下一條指令需要類似於getchar()來使用逗號。 否則,在下一個循環中不會讀取任何內容,因為stdin中的第一個字符是相同的逗號。

暫無
暫無

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

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