Question

I have been supplied a CSV line parser to use in a program, and it seems to have a bug where if there is a blank line at the end of the text file it prints out an empty line, like so

My input is this

test, does, this, work
1, second, line, same

My output looks like this. Not only does it cut off the last word, but it prints out the empty line.

test = 1
 does =  second
 this =  line
 work =  same
test =

What it's supposed to do is match every word with the coinciding one in the top line, which it does, but I don't know where the last "test = " is coming from. Here's the code I was supplied, any ideas about what's wrong with it would be a huge help. Thanks.

/*
 * Just an array of characters representing a single filed.
 */

typedef char f_string[MAX_CHARS+1] ;    /* string for each field */

/*
 * A parsed CSV line, with the number of fields and upto MAX_FIELDS themselves.
*/

typedef struct {
    int nfields ;               /* 0 => end of file */
    f_string field[MAX_FIELDS] ;        /* array of strings for fields */
} csv_line ;

/*
 * Returns true iff the character 'ch' ends a field. That is, ch is end of file,
 * a comma, or a newline.
 */

bool is_end_of_field(char ch) {
    return (ch == ',') || (ch == '\n') || (ch == EOF) ;
}

/*
 * Return the minimum of two integers.
 */

int min(int x, int y) {
    return x < y ? x : y ;
}

/*
 * Read the next field from standard input. Returns the value of getchar() that
 * stopped (terminated) the field.
 */

int get_field(f_string field) {
/**BEGIN_SOLN**/
    int i ;
    int next_char ;

    next_char = getchar() ;
    for ( i = 0 ; ! is_end_of_field(next_char) ; ++i ) {
        field[i] = next_char ;
        next_char = getchar() ;
    }

    field[i] = '\0' ;
    return next_char ;
/**END_SOLN**/
}

/*
 * Read in a CSV line. No error checking is done on the number of fields or
 * the size of any one field.
 * On return, the fields have been filled in (and properly NUL-terminated), and
 * nfields is the count of the number of valid fields.
 * nfields == 0 means end of file was encountered.
 */

csv_line get_line() {
/**BEGIN_SOLN**/
    csv_line line ;
    int fi = 0 ;    /* index of current field in line */
    int stop_ch ;   /* character that terminated the last field */

    stop_ch = get_field(line.field[fi++]) ;
    while ( stop_ch == ',' ) {
        stop_ch = get_field(line.field[fi++]) ;
    }

    line.nfields = (stop_ch == EOF) ? 0 : fi ;
    return line ;
/**END_SOLN**/
}

/*
 * Print a CSV line, associating the header fields with the
 * data line fields.
 * The minimum of the number of fields in the header and the data
 * determines how many fields are printed.
 */

void print_csv(csv_line header, csv_line data) {
/**BEGIN_SOLN**/
    int i ;
    int nfields = min(header.nfields, data.nfields) ;

    for ( i = 0 ; i < nfields ; ++i ) {
        printf("%s = %s\n", header.field[i], data.field[i]) ;
    }
/**END_SOLN**/
}

/*
 * Driver - read a CSV line for the header then read and print data lines
 * until end of file.
 */

int main() {
    csv_line header ;
    csv_line current ;

    header = get_line() ;
    current = get_line() ;

    while ( current.nfields > 0 ) {
        print_csv(header, current) ;
        current = get_line() ;
    }

    return 0 ;
}
Était-ce utile?

La solution

bool is_end_of_field(int ch) {
    return (ch == ',') || (ch == '\n') || (ch == EOF) ;
}

bool get_field(f_string field){
    int i ;
    int next_char ;
    for ( i = 0 ; ! is_end_of_field(next_char=getchar()) ; ++i ) {
        field[i] = next_char ;
    }
    field[i] = '\0';
    return (next_char == ',')? true :  false;
}

csv_line get_line() {
    csv_line line ;
    int fi = 0;
    while(get_field(line.field[fi++]))
        ;
    line.nfields = line.field[fi-1][0] ? fi : 0;
    return line ;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top