我正在做一个关于为用户提供路线的C程序分配。一开始,我得到一些关于stop_id,位置等的数据。
样本数据是这样的
location_type, parent_station, stop_id, stop_code, stop_name, stop_desc, stop_lat, stop_lon, zone_id 0,,10000,10000,"Albany Hwy After Armadale Rd","",-32.1479054960,116.0201957650,4 0,,10001,10001,"Albany Hwy After Frys L","",-32.1449537724,116.0183152090,3
我需要的信息是stop_id,stop_code,stop_name,stop_lat和stop_lon。 鉴于我应该尝试不使用strtok()
,过滤掉这些列的有用方法是什么?
答案 0 :(得分:0)
假设您有一个$ heroku config:set DJANGO_SETTINGS_MODULE=mysite.settings.prod
或char*
,其中包含您所在行中名为char[]
的字符。
您可以保留一些指向包含逗号分隔字符串中所需元素的子字符串的开头和结尾的指针,然后循环遍历字符串中的所有字符。
如果您有有效的开始和结束位置,请执行input
以获取感兴趣的字符,并将NUL终止符添加到您刚复制的字符串中:
memcpy()
获取字段的值只是取消引用正确的条目索引(即#define MAX_LEN 512
#define MAX_ENTRIES 9
/* run the following for each line of input */
char* start = &input[0];
char* end = &input[0];
char entry[MAX_ENTRIES][MAX_LEN];
uint32_t entry_idx = 0;
int finished = 0; // false
do {
end = strchr(start, ',');
if (!end) {
end = input + strlen(input);
finished = 1;
}
memcpy(entry[entry_idx], start, end - start);
entry[entry_idx][end - start] = '\0';
entry_idx++;
start = end + 1;
} while (!finished);
为entry[2]
,stop_id
为entry[3]
等。
请注意,您解除引用的是stop_code
,因此任何数值都可能需要转换为整数或浮点值,具体取决于您需要导出的内容。像char[]
等函数可以在这里提供帮助。
答案 1 :(得分:0)
假设这里的主要任务是将字符串拆分为给定分隔符的子字符串(在本例中为,
),可以执行以下操作。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE * fp;
char * line = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("data.csv", "r");
if (fp == NULL)
return 1;
getline(&line, &len, fp); // ignore first line
while ((read = getline(&line, &len, fp)) != -1)
{
unsigned int begin[10], leng[10];
int i = 0, j = 0, k = 0;
begin[0] = 0;
j++;
for (i = 0; i < read; ++i)
{
if (line[i] == ',')
{
begin[j] = i+1;
leng[k] = i-begin[j-1];
j++;
k++;
}
else if (line[i] == '\n')
{
leng[k] = i-begin[j-1];
k++;
}
}
for (i = 0; i < j; ++i)
printf("(%.*s)\n", leng[i], &line[begin[i]]);
}
fclose(fp);
if (line)
free(line);
return 0;
}
起初我正在逐行忽略第一个文件。通过迭代一行的每个字符,我保存每列的开头和长度的索引。之后,为方便起见,我打印出每一栏。
答案 2 :(得分:0)
如果我正确理解您的问题,您正在尝试编写CSV解析器。 CSV非常便于用于数据交换,但由于可能存在极端情况(ref),我通常使用专用库:
恕我直言,如果您想手动 (正如您所说不能使用strtok
),您应该:
fgetc
\r
)\n
)或文件结尾时返回完整记录(char **)如果您知道字段数,则编码会更简单。
如果它可以提供帮助,这里是一个与RFC 4180 csv数据文件兼容的解析器示例。它解析输入文件并重复调用带有C字符串数组(空终止的char数组)作为参数的回调函数。数组本身以空指针终止。它正确接受引用字段中的引号,分隔符和新行:
enum retval { OK = 0, MEMALLOC, SYNTAX, UNTERM, ABORT };
int add(char **line, unsigned int index, char c, size_t *size) {
if (index >= *size - 1) {
char *buf = realloc(*line, *size *2);
if (buf == NULL) {
return -1;
}
*size *= 2;
*line = buf;
}
(*line)[index] = c;
return 0;
}
int csvparse(FILE *fd, char delim, char quote, int *linenum, int *pos,
int (*process)(char **)) {
enum { BEFORE, FIELD, QFIELD, AFTER} mode = BEFORE;
int c;
unsigned int index = 0, findex = 0;
size_t linesize = 1024;
size_t maxFields = 256;
char **fields = calloc(maxFields, sizeof(char *));
char *line = malloc(linesize);
enum retval retval = OK;
if (linenum != NULL) *linenum = 1;
if (pos != NULL) *pos = 0;
if (quote == 0) quote = '"';
if (delim == 0) delim = ',';
fields[0] = line;
while ((c = fgetc(fd)) != EOF) {
if (pos != NULL) *pos += 1;
if (mode == QFIELD) {
if (c == quote) {
c = fgetc(fd);
if (c != quote) {
ungetc(c, fd);
mode = AFTER;
continue;
}
}
if (add(&line, index++, c, &linesize) != 0) {
retval = MEMALLOC;
break;
}
}
else if (c == quote) {
mode = QFIELD;
}
else if (c == delim) {
if (add(&line, index++, '\0', &linesize) != 0) {
retval = MEMALLOC;
break;
}
if (findex >= maxFields - 2) {
void * buf = realloc(fields, maxFields * 2);
if (buf == NULL) {
retval = MEMALLOC;
break;
}
maxFields *= 2;
fields = buf;
}
fields[++findex] = line + index;
mode = BEFORE;
}
else if (c == '\n') {
if (add(&line, index++, '\0', &linesize) != 0) {
retval = MEMALLOC;
break;
}
if (mode == FIELD) {
char *lastf = fields[findex];
char *last = lastf + strlen(lastf) -1;
while (isspace(*last) && (last > lastf)) {
*(last--) = '\0';
}
}
fields[findex + 1] = NULL;
if (process(fields) == -1) {
retval = ABORT;
break;
}
if (linenum != NULL) *linenum += 1;
if (pos != NULL) *pos = 0;
index = findex = 0;
mode = BEFORE;
}
else if (((mode == AFTER) || (mode == BEFORE)) && isspace(c)) {
;
}
else {
if (mode == BEFORE) mode = FIELD;
else if (mode == AFTER) {
retval = SYNTAX;
break;
}
if (add(&line, index++, c, &linesize) != 0) {
retval = MEMALLOC;
break;
}
}
}
if (add(&line, index++, c, &linesize) != 0) {
retval = MEMALLOC;
}
if (mode == QFIELD) {
retval = UNTERM;
}
if ((retval == OK) && ((mode != BEFORE) || (findex != 0))) {
process(fields);
}
free(line);
free(fields);
return retval;
}