I\'m trying to produce code to read input from a comma separated text file line by line. I\'m only interested in 3 of the fields, so I\'m skipping over the rest. Problem is
The following is a basic CSV parser:
void readCSVline(char *line);
char *readCSVfield(char *line, char *buf);
void readCSVdemo(void)
{
char line[]= "0,,10004,10004,\"Albany Hwy After Galliers Av\",\"\",-32.13649428,116.0176090070,3";
readCSVline(line);
}
/* readCSVline is where you put your "intelligence* about fields to read
* and what to do with them
*/
void readCSVline(char *line)
{
char field1[80], *lineptr=line;
int nfields=0;
while (*lineptr) {
lineptr= readCSVfield(lineptr, field1);
printf("%s\n", field1);
nfields++;
}
printf("%d fields read.\n", nfields);
}
/* readCSVfield reads a field from a CSV line until the next comma or end-of-line.
* It returns where the reading stopped.
*/
char *readCSVfield(char *line, char *buf)
{
int instr= FALSE; // track whether we are in a string
char *cptr= line;
while (*cptr)
{
if (instr) {
if (*cptr=='"') {
char cc= *++cptr;
if (cc=='"') // escaped double quote
*buf++ = '"';
else {
*buf='\0';
cptr--;
instr= FALSE;
}
}
else *buf++ = *cptr;
}
else switch (*cptr) {
case '"': instr= TRUE; break;
case ',': cptr++; *buf= '\0'; return(cptr);
case ' ': case '\t': case '\n': case '\r': break;
default: *buf++ = *cptr;
}
cptr++;
}
*buf= '\0';
return(cptr);
}
Note: processing linefeeds in a quoted string
Often the parser is called with a line that the caller has read. To be able to process carriage return/linefeeds that are in a quoted string, the parser must process seeing a \n
by getting the next line. The signature for readCSVfield
should then include the line buffer and its size.