如何在 C 中解析带引号的 .csv 文件
How to parse a .csv file with quotation marks in C
假设我正在尝试解析的字符串读取
"Smith, John",Data1,Data2,Data3
我还可以得到读作
的行
Dave, Data1,Data2,Data3
所以我有 if 语句
line 是文件中 fgets()
的文本行,但我认为行得通
剩下的我已经苦苦挣扎了大约一个小时了。我正在尝试重新格式化 "Smith, John" 使其成为 John Smith,然后将其分配给 recTemp.artist
if (line[0] == '\"') {
//Read the last name, first name",
char lastTemp[30] = "";
char firstTemp[30] = "";
strcpy(lastTemp , strtok(line, ", "));
strcpy(firstTemp, strtok(NULL, "\","));
char * t;
t = strstr(lastTemp, "\"");
strcpy(t, " ");
//Concatenate each string assign to the artist value
strcat(firstTemp, lastTemp);
strcpy(recTemp.artist, firstTemp);
}
我认为错误来自 strstr 调用或紧随其后的 strcpy,但我不确定
谢谢!
回答你的问题:
"I'm trying to reformat the "Smith, John" so its John Smith"
如果不使用正则表达式从字符串中提取引号,我会执行以下操作,
#include <iostream>
#include <cstring>
#include <stdio.h>
int main() {
char line[100] = "\"Smith,John\",Data1,Data2,Data3";
// fgets(line, 100, stdin);
char* name = strtok(line, "\"");
char *substring2 = strtok(NULL, "\"");
char* LastName = strtok(name, ",");
char* FirstName = strtok(NULL, ",");
char result[100];
strcpy(result, FirstName);
strcat(result, ",");
strcat(result, LastName);
strcat(result, substring2);
printf("%s",result);
}
产生输出:
John,Smith,Data1,Data2,Data3
如果你想避免用 strtok
改变 line
,你可以简单地使用指针算法将 "first last"
复制到 recTemp.artist
,或者复制 "name"
] 在第一个字段中没有引号的情况下。这只是您可以采用的另一种避免修改原始字符串的方法。 (以及使用指针的健康锻炼)
在引号存在的情况下,您可以将指针 (p
) 设置为 line + 1
并使用 strstr
查找子字符串 "\","
设置结束指向收盘价的指针 (endptr
)。然后,您可以使用 ','
在 p
上调用 strchar
以定位 last, first
之间的逗号并设置另一个指针以前进到名字的开头(firstp
).一旦 firstp
指向名字的开头,您可以将名字 memcpy
指向 recTemp.artist
,添加一个 space
,然后复制姓氏,接下来是 nul 终止。
在没有引号的情况下,只需要用strchr
定位到','
字段分隔符,然后调用memcpy
,然后nul-terminate。
一个简短的例子是:
#include <stdio.h>
#include <string.h>
typedef struct {
char artist[64];
} rec_t;
int main (void) {
#ifndef NOQUOTE
char line[] = "\"Smith, John\",Data1,Data2,Data3";
#else
char line[] = "Dave,Data1,Data2,Data3";
#endif
rec_t recTemp;
if (*line == '\"') { /* if double-quotes are present */
char *p = line + 1, *endptr, *sep; /* ptr, endptr & sep */
if (!(endptr = strstr (p, "\","))) { /* find close quote, validate */
fputs ("error: invalid line format.\n", stderr);
/* handle error as needed, e.g. */
return 1;
}
if ((sep = strchr (p, ','))) { /* locate ',' in last, first */
char *firstp = sep + 1; /* set firstp to next char */
while (*firstp && *firstp == ' ') /* skip any leading spaces */
firstp++;
memcpy (recTemp.artist, firstp, endptr - firstp); /* copy first */
endptr = recTemp.artist + (endptr-firstp); /* set endptr after */
*endptr++ = ' '; /* add a space */
memcpy (endptr, p, sep - p); /* copy last */
*(endptr + (sep - p)) = 0; /* nul-terminate */
}
}
else { /* otherwise - name without quotes */
char *sep = strchr (line, ','); /* find field seperator */
if (!sep) {
fputs ("error: invalid line format.\n", stderr);
/* handle error as needed, e.g. */
return 1;
}
memcpy (recTemp.artist, line, (sep - line)); /* copy name */
*(recTemp.artist + (sep - line)) = 0; /* nul-terminate */
}
printf ("recTemp.artist: '%s'\n", recTemp.artist);
}
例子Use/Output
$ ./bin/rectmp
recTemp.artist: 'John Smith'
使用 -DNOQUOTE
编译的不带引号的名称大小写:
$ ./bin/rectmpnq
recTemp.artist: 'Dave'
无论您使用 strtok
还是向下走几步 line
,都可以。如果你想保持 line
不变,那么要么在使用 strtok
对副本进行操作之前制作一个副本,要么只使用指针算法。您可以转储在这两种方法上生成的程序集,以查看您的编译器是否在这两种方法之间提供了优化优势。在宏伟的计划中,差异可以忽略不计。
假设我正在尝试解析的字符串读取
"Smith, John",Data1,Data2,Data3
我还可以得到读作
的行Dave, Data1,Data2,Data3
所以我有 if 语句
line 是文件中 fgets()
的文本行,但我认为行得通
剩下的我已经苦苦挣扎了大约一个小时了。我正在尝试重新格式化 "Smith, John" 使其成为 John Smith,然后将其分配给 recTemp.artist
if (line[0] == '\"') {
//Read the last name, first name",
char lastTemp[30] = "";
char firstTemp[30] = "";
strcpy(lastTemp , strtok(line, ", "));
strcpy(firstTemp, strtok(NULL, "\","));
char * t;
t = strstr(lastTemp, "\"");
strcpy(t, " ");
//Concatenate each string assign to the artist value
strcat(firstTemp, lastTemp);
strcpy(recTemp.artist, firstTemp);
}
我认为错误来自 strstr 调用或紧随其后的 strcpy,但我不确定
谢谢!
回答你的问题:
"I'm trying to reformat the "Smith, John" so its John Smith"
如果不使用正则表达式从字符串中提取引号,我会执行以下操作,
#include <iostream>
#include <cstring>
#include <stdio.h>
int main() {
char line[100] = "\"Smith,John\",Data1,Data2,Data3";
// fgets(line, 100, stdin);
char* name = strtok(line, "\"");
char *substring2 = strtok(NULL, "\"");
char* LastName = strtok(name, ",");
char* FirstName = strtok(NULL, ",");
char result[100];
strcpy(result, FirstName);
strcat(result, ",");
strcat(result, LastName);
strcat(result, substring2);
printf("%s",result);
}
产生输出:
John,Smith,Data1,Data2,Data3
如果你想避免用 strtok
改变 line
,你可以简单地使用指针算法将 "first last"
复制到 recTemp.artist
,或者复制 "name"
] 在第一个字段中没有引号的情况下。这只是您可以采用的另一种避免修改原始字符串的方法。 (以及使用指针的健康锻炼)
在引号存在的情况下,您可以将指针 (p
) 设置为 line + 1
并使用 strstr
查找子字符串 "\","
设置结束指向收盘价的指针 (endptr
)。然后,您可以使用 ','
在 p
上调用 strchar
以定位 last, first
之间的逗号并设置另一个指针以前进到名字的开头(firstp
).一旦 firstp
指向名字的开头,您可以将名字 memcpy
指向 recTemp.artist
,添加一个 space
,然后复制姓氏,接下来是 nul 终止。
在没有引号的情况下,只需要用strchr
定位到','
字段分隔符,然后调用memcpy
,然后nul-terminate。
一个简短的例子是:
#include <stdio.h>
#include <string.h>
typedef struct {
char artist[64];
} rec_t;
int main (void) {
#ifndef NOQUOTE
char line[] = "\"Smith, John\",Data1,Data2,Data3";
#else
char line[] = "Dave,Data1,Data2,Data3";
#endif
rec_t recTemp;
if (*line == '\"') { /* if double-quotes are present */
char *p = line + 1, *endptr, *sep; /* ptr, endptr & sep */
if (!(endptr = strstr (p, "\","))) { /* find close quote, validate */
fputs ("error: invalid line format.\n", stderr);
/* handle error as needed, e.g. */
return 1;
}
if ((sep = strchr (p, ','))) { /* locate ',' in last, first */
char *firstp = sep + 1; /* set firstp to next char */
while (*firstp && *firstp == ' ') /* skip any leading spaces */
firstp++;
memcpy (recTemp.artist, firstp, endptr - firstp); /* copy first */
endptr = recTemp.artist + (endptr-firstp); /* set endptr after */
*endptr++ = ' '; /* add a space */
memcpy (endptr, p, sep - p); /* copy last */
*(endptr + (sep - p)) = 0; /* nul-terminate */
}
}
else { /* otherwise - name without quotes */
char *sep = strchr (line, ','); /* find field seperator */
if (!sep) {
fputs ("error: invalid line format.\n", stderr);
/* handle error as needed, e.g. */
return 1;
}
memcpy (recTemp.artist, line, (sep - line)); /* copy name */
*(recTemp.artist + (sep - line)) = 0; /* nul-terminate */
}
printf ("recTemp.artist: '%s'\n", recTemp.artist);
}
例子Use/Output
$ ./bin/rectmp
recTemp.artist: 'John Smith'
使用 -DNOQUOTE
编译的不带引号的名称大小写:
$ ./bin/rectmpnq
recTemp.artist: 'Dave'
无论您使用 strtok
还是向下走几步 line
,都可以。如果你想保持 line
不变,那么要么在使用 strtok
对副本进行操作之前制作一个副本,要么只使用指针算法。您可以转储在这两种方法上生成的程序集,以查看您的编译器是否在这两种方法之间提供了优化优势。在宏伟的计划中,差异可以忽略不计。