使用txt文件输入在C中过滤数据列

时间:2015-09-07 08:00:16

标签: c arrays string text io

我正在做一个关于为用户提供路线的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() ,过滤掉这些列的有用方法是什么?

3 个答案:

答案 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_identry[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
  • 一次读取输入的一个字符
  • 如果在带引号的字符串中:
    • 收集所有不是报价的内容
    • 如果你得到2
    • ,请收集报价
    • 当您发现引号后面没有第二个
    • 时,结束引用的字符串
  • 否则:
    • 传递给逗号
    • 的下一个字段
    • 忽略空白字符(空格,制表符和\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;
}