将.csv文件分隔为列?

x9ybnkn6  于 9个月前  发布在  其他
关注(0)|答案(1)|浏览(88)

我有一个项目要做一个程序,读取一个.csv文件,需要两个输入,第一个输入是列,第二个输入是关键词。它需要做的是找到所选列中的关键词,并打印出该列中包含该关键词的每一行。我已经在这个问题上卡住了一段时间,只是无法弄清楚。
问题从第75行开始,在那里我得到一个错误“request for member 'Location1' in 'aol',它是非类类型'data [4000]”

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

struct data{
    char Location1[100];
    char Location2[100];
    char price[10];
    char rooms[10];
    char bathrooms[10];
    char carparks[10];
    char type[100];
    char furnish[100];
};

struct data aol[4000];
int printedlines;

// Untuk membaca isi file csv
void fileread() {
    FILE *fp = fopen("AOLDATA.csv","r");
    if(fp == NULL){
        printf("Error! File not found.");
        exit(0);
    }
    while(fscanf(fp, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\n]", aol[printedlines].Location1, aol[printedlines].Location2,
    aol[printedlines].price, aol[printedlines].rooms, aol[printedlines].bathrooms, aol[printedlines].carparks,
    aol[printedlines].type, aol[printedlines].furnish) != EOF) {
        printedlines++;
        fgetc(fp);
    }
    fclose(fp);
}

void searchData(char *keyword) {
    int found = 0;
    for(int i = 0; i < printedlines; i++) {
        if(strstr(aol[i].Location1, keyword) || strstr(aol[i].Location2, keyword) ||
           strstr(aol[i].price, keyword) || strstr(aol[i].rooms, keyword) ||
           strstr(aol[i].bathrooms, keyword) || strstr(aol[i].carparks, keyword) ||
           strstr(aol[i].type, keyword) || strstr(aol[i].furnish, keyword)) {
            printf("%-20s%-20s%-20s%-20s%-20s%-20s%-20s%-20s\n", aol[i].Location1, aol[i].Location2, aol[i].price, aol[i].rooms,
            aol[i].bathrooms, aol[i].carparks, aol[i].type, aol[i].furnish);
            found++;
        }
    }
    if(!found) {
        printf("Data not found!");
    }
}

int main(){
    int option;
    char line[100];
    
    fileread();
    
    printf("What do you want to do?\n1.Display data\n2.Search Data\n3.Sort Data\n4.Export Data\n5.Exit\n");
    printf("Your choice: ");
    scanf("%d", &option);
    
    
    if(option == 1){
    int howmanylines;
    int printedlines = 0;
    printf("Number of rows: ");
    scanf("%d", &howmanylines);
    for(int i = 0; i < howmanylines; i++) {
        printf("%-20s%-20s%-20s%-20s%-20s%-20s%-20s%-20s\n", aol[i].Location1, aol[i].Location2, aol[i].price, aol[i].rooms,
        aol[i].bathrooms, aol[i].carparks, aol[i].type, aol[i].furnish);
    }

    }else if(option == 2){
            char choice[100];
            char column[100];
            
            printf("Choose column: ");
            scanf("%s", column); getchar();
            printf("What do you want to find? ");
            scanf("%s", choice); getchar();
            
            
            if(choice == aol.Location1){
                for(int i=0; i < 3940-1; i+8)
                printf("%-20s%-20s%-20s%-20s%-20s%-20s%-20s%-20s\n", aol[i].Location1, aol[i].Location2, aol[i].price, aol[i].rooms
                , aol[i].bathrooms, aol[i].carparks, aol[i].type, aol[i].furnish);
            }
        }
        
    return 0;
}

字符串
输入文件示例:

A   B   C   D   E   F     G      H
NY  US  10  20  30  40   Bad   Expensive
LN  UK  20  30  40  50   Good  Expensive
JK  IN  20  10  50  20   Good  Cheap

mspsb9vt

mspsb9vt1#

  1. choice == aol.Location1:比较两个指针(这里总是false),而不是使用strcmp()来比较字符串。
    1.对于search,不清楚你是想在结构成员名上搜索,还是第一行是一个header,你想输入一个header列名。我使用了前者,因为它少了一步,但如果你澄清你想要后者,我会更新我的答案。
    1.(不固定)如果第一行是一个标题,那么你想为它使用一个不同的类型,比如说,char **header,因为它没有数据的约束。如果列的类型是int,那么列标题仍然是char *
    1.(不固定)考虑使用一个更简单的数据模型。例如一个线数组(char **data)。然后一切都会变得更容易处理:
header_print(header);
int column = header_column(header, name)
for(size_t i = 0; i < n; i++)
   if(!strcmp(column_value(data[i], column), value))
     // ...

字符串
1.在使用scanf()阅读字符串时,始终使用最大字段宽度,以避免缓冲区溢出。我引入了字符串长度的符号常量,并使用str()宏生成合适的格式字符串。
1.始终检查fprintf()scanf()等I/O操作的返回值,否则可能会对未初始化的变量进行操作。
1.使用符号常量,如字段的数量或每个选项的名称,而不是硬编码,特别是如果你需要多次使用它。
1.不要使用全局变量,这会让你的代码更难测试。
1.重新格式化菜单以提高可读性。

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

#define FIELDS 8
#define LOCATION_LEN 99
#define FURNISH_LEN 99
#define TYPE_LEN 99
#define STR_LEN 9
#define str(s) str2(s)
#define str2(s) #s

struct data {
    char Location1[LOCATION_LEN+1];
    char Location2[LOCATION_LEN+1];
    char price[STR_LEN+1];
    char rooms[STR_LEN+1];
    char bathrooms[STR_LEN+1];
    char carparks[STR_LEN+1];
    char type[TYPE_LEN+1];
    char furnish[FURNISH_LEN+1];
};

void fileread(const char *path, struct data **aol, size_t *n) {
    FILE *fp = fopen(path, "r");
    if(!fp){
        fprintf(stderr, "Error! File not found.");
        exit(1);
    }
    *aol = NULL;
    for(*n = 0;; (*n)++) {
        struct data r;
        int rv = fscanf(fp,
            " %" str(LOCATION_LEN) "[^,],"
            "%" str(LOCATION_LEN) "[^,],"
            "%" str(STR_LEN) "[^,],"
            "%" str(STR_LEN) "[^,],"
            "%" str(STR_LEN) "[^,],"
            "%" str(STR_LEN) "[^,],"
            "%" str(TYPE_LEN) "[^,],"
            "%" str(FURNISH_LEN) "[^\n]",
            r.Location1,
            r.Location2,
            r.price,
            r.rooms,
            r.bathrooms,
            r.carparks,
            r.type,
            r.furnish
        );
        if(rv == EOF)
            break;
        if(rv != FIELDS) {
            fprintf(stderr, "invalid input line %zu\n", *n+1);
            exit(1);
        }
        struct data *tmp = realloc(*aol, sizeof *tmp * (*n + 1));
        if(!tmp) {
            fprintf(stderr, "realloc failed\n");
            exit(1);
        }
        *aol = tmp;
        (*aol)[*n] = r;
    }
    fclose(fp);
}

int name_offset(const char *name, size_t *offset) {
    if(!name) return -1;
#define MAP(name) {#name, offsetof(struct data, name)}

    struct {
        const char *name;
        size_t offset;
    } map[] = {
        MAP(Location1),
        MAP(Location2),
        MAP(price),
        MAP(rooms),
        MAP(bathrooms),
        MAP(carparks),
        MAP(type),
        MAP(furnish)
    };
    for(size_t i = 0; i < sizeof map / sizeof *map; i++)
        if(!strcmp(name, map[i].name)) {
            *offset = map[i].offset;
            return 0;
        }
    return -1;
}

void search(const struct data *aol, size_t n, const char *name, const char *value) {
    size_t offset;
    if(name && name_offset(name, &offset)) {
        fprintf(stderr, "column name %s was not found\n", name);
        return;
    }
    for(int i = 0; i < n; i++)
        if(!name || !strcmp(((char *) &aol[i])+offset, value))
            printf(
                "%-20s%-20s%-20s%-20s%-20s%-20s%-20s%-20s\n",
                aol[i].Location1,
                aol[i].Location2,
                aol[i].price,
                aol[i].rooms,
                aol[i].bathrooms,
                aol[i].carparks,
                aol[i].type,
                aol[i].furnish
            );
}

int main(void) {
    struct data *aol;
    size_t n;
    fileread("AOLDATA.csv", &aol, &n);

    enum {DISPLAY = 1, SEARCH, SORT, EXPORT, EXIT};
    printf(
        "What do you want to do?\n"
        "%d.Display data\n"
        "%d.Search Data\n"
        //"%d.Sort Data\n"
        //"%d.Export Data\n"
        "%d.Exit\n"
        "Your choice: ",
        DISPLAY,
        SEARCH,
        // SORT,
        // EXPORT,
        EXIT
    );
    int option;
    if(scanf("%d", &option) != 1 || option < DISPLAY || option > EXIT) {
        fprintf(stderr, "invalid option\n");
        exit(1);
    }

    if(option == DISPLAY) {
        search(aol, n, NULL, NULL);
    } else if(option == SEARCH) {
        char name[LOCATION_LEN+1];
        printf("Choose column: ");
        scanf(" %" str(LOCATION_LEN) "s", name);

        printf("What do you want to find? ");
        char value[LOCATION_LEN+1];
        scanf(" %" str(LOCATION_LEN) "s", value);

        search(aol, n, name, value);
    }
    free(aol);
}


我修改了你的输入文件以匹配你的解析器:

A,B,C,D,E,F,G,H
NY,US,10,20,30,40,Bad,Expensive
LN,UK,20,30,40,50,Good,Expensive
JK,IN,20,10,50,20,Good,Cheap


示例运行:

$ ./a.out
What do you want to do?
1.Display data
2.Search Data
5.Exit
Your choice: 1
A                   B                   C                   D                   E                   F                   G                   H                   
NY                  US                  10                  20                  30                  40                  Bad                 Expensive           
LN                  UK                  20                  30                  40                  50                  Good                Expensive           
JK                  IN                  20                  10                  50                  20                  Good                Cheap
$ ./a.out
What do you want to do?
1.Display data
2.Search Data
5.Exit
Your choice: 2
Choose column: furnish
What do you want to find? Expensive
NY                  US                  10                  20                  30                  40                  Bad                 Expensive           
LN                  UK                  20                  30                  40                  50                  Good                Expensive

相关问题