how to get specific rows from csv file with exact data using c?

断了今生、忘了曾经 提交于 2020-03-05 06:06:02

问题


This is my csv file, i want to get only those row which start with character "A" so i got my output but with some addition column as '0' please help me to find were i went wrong?

And one more thing i want to remove specific column like bread,anName,ot

Name,id,bread,anName,Ot,number
A,1,animal,tiger,op,8.1
M,2,animal,toper,ip,9.1
A1,7,animal,dog,cp,Na11
A2,9,animal,mouse,ap,0
A23,9,animal,pouch,gp,Na11


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

#define NUMLETTERS 100

typedef struct {
    char Name[100];
    int id;
    char number[100];
} record_t;

int main(void) {
    FILE *fp;
    record_t records[NUMLETTERS];
    int count = 0, i;

    fp = fopen("letter.csv", "r");
    if (fp == NULL) {
        fprintf(stderr, "Error reading file\n");
        return 1;
    }

    while (fscanf(fp, "%s,%d,%s", records[count].name, &records[count].id, records[count].number) == 1) 
        count++;

    for (i = 0; i < count; i++) {
        if(records[i].Name[0] == 'A'){
            printf("%s,%d,%s\n", records[i].Name, records[i].id, records[i].number);
        }
    }

    fclose(fp);

    return 0;
}

i want output as:

A,1,8.1
A1,7,Na11
A2,9,0
A23,9,Na11


回答1:


You have two problems:

  1. The %s format specifier tells fscanf to read a space-delimited string. Since the the records aren't space-delimited the first %s will read the whole line.

  2. The fscanf function returns the number of successfully parsed elements it handled. Since you attempt to read three values you should compare with 3 instead of 1.


Now for one way how to solve the first problem: Use the %[ format specifier. It can handle simple patterns and, most importantly, negative patterns (read while input does not match).

So you could tell fscanf to read a string until it finds a comma by using %[^,]:

fscanf(fp, " %[^,],%d,%s", records[count].Refdes, &records[count].pin, records[count].NetName)

The use of the %[ specifier is only needed for the first string, as the second will be space-delimited (the newline).

Also note that there's a space before the %[ format, to read and ignore leading white-space, like for example the newline from the previous line.




回答2:


i want to get only those row which start with character "A"

i want to remove the number which coming between A and tiger,

If I understand you correctly and you only want to store rows beginning with 'A', then I would adjust your approach to read each line with fgets() and then check whether the first character in the buffer is 'A', if so, continue; and get the next line. The for those lines that do start with 'A', simply use sscanf to parse the data into your array of struct records.

For your second part of removing the number between 'A' and "tiger", there is a difference between what you store and what you output (this comes into play in storing only records beginning with 'A' as well), but for those structs stored where the line starts with 'A', you can simply not-output the pin struct member to get the output you want.

The approach to reading a line at a time will simply require that you declare an additional character array (buffer), called buf below, to read each line into with fgets(), e.g.

    char buf[3 * NUMLETTERS] = "";
    ...
    /* read each line into buf until a max of NUMLETTERS struct filled */
    while (count < NUMLETTERS && fgets (buf, sizeof buf, fp)) {   
        record_t tmp = { .Refdes = "" };    /* temporary struct to read into */
        if (*buf != 'A')                    /* if doesn't start with A get next */
            continue;
        /* separate lines beginning with 'A' into struct members */
        if (sscanf (buf, " %99[^,],%d,%99[^\n]",
                    tmp.Refdes, &tmp.pin, tmp.NetName) == 3)
            records[count++] = tmp;         /* assign tmp, increment count */
        else
            fprintf (stderr, "%d A record - invalid format.\n", count + 1);
    }

A short example putting that to use and (since we are not sure what "remove" is intended to be), we have included a pre-processor conditional that will only output the .Refdes and .NetName members by default, but if you either #define WITHPIN or include the define in your compile string (e.g. -DWITHPIN) it will output the .pin member as well.

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

#define NUMLETTERS 100

typedef struct {
    char Refdes[NUMLETTERS];
    int pin;
    char NetName[NUMLETTERS];
} record_t;

int main (int argc, char **argv) {

    record_t records[NUMLETTERS];
    char buf[3 * NUMLETTERS] = "";
    int count = 0, i;
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    /* read each line into buf until a max of NUMLETTERS struct filled */
    while (count < NUMLETTERS && fgets (buf, sizeof buf, fp)) {   
        record_t tmp = { .Refdes = "" };    /* temporary struct to read into */
        if (*buf != 'A')                    /* if doesn't start with A get next */
            continue;
        /* separate lines beginning with 'A' into struct members */
        if (sscanf (buf, " %99[^,],%d,%99[^\n]",
                    tmp.Refdes, &tmp.pin, tmp.NetName) == 3)
            records[count++] = tmp;         /* assign tmp, increment count */
        else
            fprintf (stderr, "%d A record - invalid format.\n", count + 1);
    }

    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);

    for (i = 0; i < count; i++)
#ifdef WITHPIN
        printf ("%-8s %2d     %s\n",
                records[i].Refdes, records[i].pin, records[i].NetName);
#else
        printf ("%-8s     %s\n", records[i].Refdes, records[i].NetName);
#endif
}

Example Use/Output

$ ./bin/getaonly dat/getasonly.txt
A            tiger
A1           dog
A2           mouse
A23          pouch

If you define -DWITHPIN in your compile string, then you will get all three outputs:

$ ./bin/getaonly dat/getasonly.txt
A         1     tiger
A1        7     dog
A2        9     mouse
A23       9     pouch

(note: with the data stored in your array, you can adjust the output format to anything you need)

Since there is some uncertainty whether you want to store all and output only records beginning with 'A' or only want to store records beginning with 'A' -- let me know if I need to make changes and I'm happy to help further.



来源:https://stackoverflow.com/questions/60034462/how-to-get-specific-rows-from-csv-file-with-exact-data-using-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!