我试图仅使用stdio.h,stdlib.h和string.h库编写C程序。我想从CSV文件读取和打印。该文件的格式应为:
ID,NAME,AGE,GPA
例如:
10,bob,18,3.5
15,mary,20,4.0
5,tom,17,3.8
,但逗号前后可以有空格,如本例中的第三行所示。
我的代码应以以下格式从csv文件中打印:
记录1:ID = nnn NAME = nnn AGE = nnn GPA = nnn
,并应删除值之前或之后的空格。
我该怎么做?
这就是我现在的代码,但是当我运行代码时,ID周围的空格仍然显示
printf("Record %d: ", rec );
char* comma = strtok(file, ",")
printf("ID=%s ",comma );
comma = strtok(NULL, ",");
printf("NAME=%s ", comma );
comma = strtok(NULL, ",");
sscanf(comma, "%d", &age);
printf("Age=%d ", age);
comma = strtok(NULL, ",");
gpa = strtof(comma, NULL);
printf("GPA=%.2f \n",gpa );
答案 0 :(得分:1)
您使问题变得更加棘手。 strtok
接受 string 中提供的多个定界符,并将这些定界符的任何组合序列视为单个定界符。因此,要分析您的.csv
文件中逗号周围可能有空格的地方,只需添加" ,\n"
(空格,逗号,换行符)作为分隔符,然后strtok
将每个分隔符令牌删除逗号以及任何前导空格或尾随换行符。
这将您的代码简化为:
#include <stdio.h>
#include <string.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
#define DELIM " ,\n"
int main (void) {
char buf[MAXC]; /* buffer to hold each line */
while (fgets (buf, MAXC, stdin)) { /* read each line */
char *p = buf; /* pointer to line */
/* now simply use strtok to separate all tokens in line */
for (p = strtok(p, DELIM); p; p = strtok (NULL, DELIM))
printf ("%-8s", p); /* output as desired */
putchar ('\n'); /* tidy up with newline */
}
return 0;
}
使用/输出示例
$ ./bin/strtokcsv <dat/spacecomma.csv
10 bob 18 3.5
15 mary 20 4.0
5 tom 17 3.8
(您可以根据需要调整输出格式)。
另请参阅@Kaz的评论。一个简单的循环,其中getchar()
在状态循环中读取一次一次字符,在此循环检查字符输出的字符,这些字符不是空格,逗号或换行符,并且在您点击时空格或逗号只需插入您选择的输出分隔符,然后忽略所有后续空格,逗号等。直到到达下一个字段并再次开始输出字符。绝对值得一看。如果您还有其他问题,请告诉我。
答案 1 :(得分:1)
假设CSV数据不包含保护逗号的引号,我们可以使用不对数据进行任何缓冲或对以空终止的字符数组进行任何处理的程序来删除逗号周围的多余空格。我们只使用getchar
一次读取一个字符,并以计数器的形式维护某些状态,该计数器可测量我们已经看到了多少空格和逗号:
#include <stdio.h>
int main(void)
{
int nspc = 0;
int ncomma = 0;
int ch;
while ((ch = getchar()) != EOF) {
switch (ch) {
case ' ': nspc++; break;
case ',': ncomma++; break;
default:
if (ncomma > 0)
while (ncomma-- > 0)
putchar(',');
else
while (nspc-- > 0)
putchar(' ');
putchar(ch);
nspc = 0;
ncomma = 0;
break;
}
}
return 0;
}
测试数据:
$ cat clean-comma-test
a
aa
a,
,a
a a,
,a a
a , b
, a , b c , d
, a , b c d ef, g h
,
,a
, ,
, ,, , , ,
输出:
a
aa
a,
,a
a a,
,a a
a,b
,a,b c,d
,a,b c d ef,g h
,
,a
,,
,,,,,,
基本思想是:
如果我们看到一个N个空格的字段,其中不包含任何逗号,后跟一个不是空格或逗号的字符C,那么我们只重现N个空格和字符C。
如果我们看到一个包含一个或多个逗号M的N个空格(可能为0)的字段,后跟一个不是空格或逗号的字符C,则我们将产生M个逗号,然后是C。 / p>
行以换行符'\n'
终止,在逗号空间字段是该行的最后一项的情况下,该行用作C。
不处理任何指针的C程序不能有缓冲区溢出或内存泄漏。但是,我没有针对整数溢出保护计数器。如果您有超过INT_MAX
个空格和/或逗号的字段,则该行为是不确定的。在现代系统上,这一数字远远超过20亿,因此有足够的理由不理会它。
该代码也无法识别其他空格,例如制表符。
答案 2 :(得分:0)
char *trim(char *str, const char *chars)
{
char *end = str + strlen(str) - 1;
while(end > str)
{
if(strchr(chars, *str))
{
str++;
}
if(strchr(chars, *end))
{
*end-- = 0;
}
}
return str;
}
和
comma = trim(comma, " ");