从C中的CSV表获取价值

时间:2018-10-04 10:27:14

标签: c csv strtok

我已经在MatLab中制作了一个矩阵,并将其导出为CSV。我真的不知道如何在我的C代码中使用它。 例如,我的表看起来像这样(尽管值更大,更复杂):

Height/Angle, 50, 550, 1050, 1550, 2050
5, 0.9, 0.8, 0.7, 0.6, 0.5
6, 0.8, 0.7, 0.6, 0.5, 0.4
7, 0.7, 0.6, 0.5, 0.4, 0.3
8, 0.6, 0.5, 0.4, 0.3, 0.2
9, 0.5, 0.4, 0.3, 0.2, 0.1

所以我想要的是一个带有两个参数并从表中返回相应值的函数。我有一个程序,可以给我一个平面的高度和角度(从红外传感器看),给定这些值,我想要相应的值。例如:在我的示例中,GetValueFromCSV(550,7);应该返回0.6。但是我不知道该怎么做。我已经做了一些研究 ´strtok()`,但这似乎并不是我真正需要的。请帮助菜鸟。

1 个答案:

答案 0 :(得分:0)

。 o O(是的,仅代码回答原因代码很不言而喻)

CERT=kyiv-linux-machine3-rst-d43d7eff66aa.ovpn
CERT=kyiv-linux-machine4-rst-d43d7eff66aa.ovpn
CERT=kyiv-linux-machine5-rst-d43d7eff66aa.ovpn

输出:

#include <stddef.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

typedef struct row_tag
{
    int index;
    double *data;
} row_t;

size_t get_col_count(FILE *is)
{
    size_t col_count = 1;

    int ch;
    while ((ch = fgetc(is)) != EOF && ch != '\n')
        if (ch == ',')
            ++col_count;

    rewind(is);
    return col_count;
}

row_t* csv_read(FILE *is, size_t *cols, size_t *rows)
{
    *cols = get_col_count(is);
    *rows = 0;
    char const *origin_format = "%*[^ ,]%c";
    char const *row_header_format = "%d%c";
    char const *format = "%lf%c";
    row_t *csv = NULL;

    bool valid = true;
    for (size_t current_row = 0; valid; ++current_row) {
        csv = realloc(csv, (current_row + 1)* sizeof(row_t));
        csv[current_row].data = calloc(cols - 1, sizeof(double));

        for (size_t current_col = 0; valid && current_col < cols; ++current_col) {

            char delim;
            if (!current_col && !current_row) {
                if (fscanf(is, origin_format, &delim) != 1 || delim != ',') {
                    valid = false;
                    continue;
                }
                csv[0].index = -1;
            }
            else if (!current_col) {
                int result = -1;
                if ((result = fscanf(is, row_header_format, &csv[current_row].index, &delim)) != 2 || delim != ',') {
                    valid = false;
                    continue;
                }
            }
            else {
                if (fscanf(is, format, &csv[current_row].data[current_col - 1], &delim) != 2 || delim != ',' && delim != '\n')
                    valid = false;
            }
        }

        if (!valid)
            free(csv[current_row].data);
        else *rows = current_row + 1;
    }

    return csv;
}

void csv_free(row_t *csv, size_t rows)
{
    for (size_t row = 0; row < rows; ++row)
        free(csv[row].data);
    free(csv);
}

double csv_get_value(row_t *csv, int col_index, size_t cols, int row_index, size_t rows)
{
    size_t col;
    for (col = 1; csv[0].data[col] != col_index && col < cols; ++col);
    if (col >= cols || csv[0].data[col] != col_index)
        return 0.;

    size_t row;
    for (row = 1; csv[row].index != row_index && row < rows; ++row);
    if (row >= rows || csv[row].index != row_index)
        return 0.;

    return csv[row].data[col];
}

int main(void)
{
    char const *filename = "test.txt";
    FILE *is = fopen(filename, "r");
    if (!is) {
        fprintf(stderr, "Couldn't open \"%s\" for reading!\n\n", filename);
        return EXIT_FAILURE;
    }

    size_t cols;
    size_t rows;
    row_t *csv = csv_read(is, &cols, &rows);
    printf("Cols: %zu\nRows: %zu\n\n", cols, rows);

    fclose(is);

    // have fun with csv:
    for (size_t y = 0; y < rows; ++y) {
        printf("%2d: ", csv[y].index);
        for (size_t x = 0; x < cols - 1; ++x)
            printf("%f ", csv[y].data[x]);
        putchar('\n');
    }

    double value = csv_get_value(csv, 550, cols, 7, rows);
    printf("\n%f\n", value);


    csv_free(csv, rows);
}