首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从csv文件中读取并分离为变量

从csv文件中读取并分离为变量
EN

Stack Overflow用户
提问于 2015-11-17 15:56:42
回答 2查看 952关注 0票数 1

我试图将我的输入值分为两个不同的类别。第一个数组调用“工作组名称”将保存团队名称,而第二个数组将保存该周的得分。我的输入文件是.csv,代码的方式是,所有内容都存储在字符串中,而不是两个单独的变量。另外,我也不懂编程,我只熟悉这个库。

代码语言:javascript
复制
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

#define FILEIN "data.csv"
#define FILEOUT "matrix.csv"

int main (void)
{
    double nfl[32][32], teamscore[32];
    char teamname[30];
    int n;
    FILE *filein_ptr;
    FILE *fileout_ptr;

    filein_ptr = fopen (FILEIN, "r");
    fileout_ptr = fopen (FILEOUT, "w");

    for (n = 1; n <= 32; n++) {
        fscanf (filein_ptr, "%s  %lf\n", &teamname, &teamscore[n]);
        fprintf (fileout_ptr, "%s    %f\n", teamname, teamscore);
    }

    fclose (filein_ptr);
    fclose (fileout_ptr);

    return 0;
}

我应该说,输入文件有第一列有团队名称,第二列有团队分数。任何帮助都会很好。谢谢!下面是一个示例输入文件

  • 钢铁,20岁
  • 爱国者,25岁
  • 突袭者,15人
  • 酋长,35岁
EN

回答 2

Stack Overflow用户

发布于 2015-11-17 22:23:42

除了将&teamname更改为teamname之外,您还可能需要考虑其他几个问题。首先,始终初始化变量。虽然不是必要的,但这有一些积极的好处。对于数值数组,它初始化所有防止意外从未初始化值读取的元素。对于字符数组,初始化到0可以确保字符串的第一次复制(小于总长度)将是null-terminated,并防止尝试从未初始化的值读取。这只是个好习惯:

代码语言:javascript
复制
    double teamscore[MAXS] = {0.0};
    char teamname[30] = {0};
    int n = 0;

您已经为您的filein_ptrfileout_ptr定义了默认值,您也可以对您的数组大小进行相同的操作。如果数组大小需要更改,则提供一个要更新的值,从而使代码更易于维护。

接下来,这是一个相当重要的nit,但是一个重要的nit。main接受参数,由标准定义为int argc, char **argv (您可能还会看到Unix系统上的char **envp,您可能认为它们都是以等效形式char *argv[]char *envp[]编写的)。这里的重点是使用它们为您的程序获取参数,这样您就不会只使用硬编码的data.csvmatrix.csv文件名。您可以使用硬编码的值,还可以通过使用简单的ternary运算符(例如test ? if true code : if false code;)向用户提供输入自己选择的文件名的能力:

代码语言:javascript
复制
    FILE *filein_ptr = argc > 1 ? fopen (argv[1], "r") : fopen (FILEIN, "r");
    FILE *fileout_ptr = argc > 2 ? fopen (argv[2], "w") : fopen (FILEOUT, "w");

在这里,测试argc > 1 (意味着至少有一个由用户提供的参数),如果真代码open (argv[1], "r") (打开作为读取参数的文件名),如果假代码fopen (FILEIN, "r")打开默认的文件名,如果没有给定的文件名。输出文件也是如此。(你必须按正确的顺序提供)。

然后,如果打开文件,则必须在尝试读取文件之前验证文件是否已打开。虽然您可以分别测试输入和输出,以判断哪一个失败了,但您也可以使用一个简单的||条件来检查是否打开失败:

代码语言:javascript
复制
    if (!filein_ptr || ! fileout_ptr) {
        fprintf (stderr, "error: filein of fileout open failed.\n");
        return 1;
    }

最后,如果您知道需要读取的数据行数,则可以使用索引的for循环,但是您很少知道数据文件中的行数。即使使用for循环,仍然需要检查fscanf的返回,以验证实际有2个有效的转换(因此得到了预期的2个值)。检查回报也提供了另一个好处。它允许您继续阅读,直到您不再从fscanf获得2个有效的转换。这为从文件中读取未知数量的值提供了一种简单的方法。但是,您确实需要确保不尝试将更多的值读入数组中。例如:

代码语言:javascript
复制
    while (fscanf (filein_ptr, " %29[^,],%lf", teamname, &teamscore[n]) == 2) {
        fprintf (fileout_ptr, "%s    %f\n", teamname, teamscore[n++]);
        if (n == MAXS) {  /* check data doesn't exceed MAXS */
            fprintf (stderr, "warning: data exceeds MAXS.\n");
            break;
        }
    }

注意:当使用包含字符大小写的格式说明符(如"%[^,], ...")时,请注意,它将在字符串转换中读取并包括前导空格和尾随空格。因此,如果您的文件有' Steelers ,..'teamname将包含空格。您可以通过在开始转换之前包括一个空格(如" %29[^,], ...")来修复前导空格,还可以通过指定最大字段宽度来限制可以读取的字符数。(在这种情况下,后面的空格在读取后会更容易修剪)

将所有的代码组合在一起,您可以通过接受用户的参数并验证您的文件和读取操作,使您的代码更加灵活和可靠:

代码语言:javascript
复制
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

#define FILEIN "data.csv"
#define FILEOUT "matrix.csv"
#define MAXS 32

int main (int argc, char **argv)
{
    /* double nfl[MAXS][MAXS] = {{0}}; */
    double teamscore[MAXS] = {0.0};
    char teamname[30] = {0};
    int n = 0;
    FILE *filein_ptr = argc > 1 ? fopen (argv[1], "r") : fopen (FILEIN, "r");
    FILE *fileout_ptr = argc > 2 ? fopen (argv[2], "w") : fopen (FILEOUT, "w");

    if (!filein_ptr || ! fileout_ptr) {
        fprintf (stderr, "error: filein of fileout open failed.\n");
        return 1;
    }

    while (fscanf (filein_ptr, " %29[^,],%lf", teamname, &teamscore[n]) == 2) {
        fprintf (fileout_ptr, "%s    %f\n", teamname, teamscore[n++]);
        if (n == MAXS) {  /* check data doesn't exceed MAXS */
            fprintf (stderr, "warning: data exceeds MAXS.\n");
            break;
        }
    }

    fclose (filein_ptr);
    fclose (fileout_ptr);

    return 0;
}

测试输入

代码语言:javascript
复制
$ cat ../dat/teams.txt
Steelers,   20
Patriots,25
    Raiders,    15
    Chiefs,35

注意:值之间的前导空格和空格的变化是有意的。

使用/输出

代码语言:javascript
复制
$ ./bin/teams ../dat/teams.txt teamsout.txt

$ cat teamsout.txt
Steelers    20.000000
Patriots    25.000000
Raiders    15.000000
Chiefs    35.000000

如果你还有其他问题,请告诉我。

票数 1
EN

Stack Overflow用户

发布于 2015-11-17 19:43:02

如果要将团队名称存储在数组中,则应该声明一个二维数组:

代码语言:javascript
复制
char team_names[N_OF_TEAMS][MAX_CHAR_IN_NAME];

然后,为分数声明数组。你用双打来存储分数,不是只有整数吗?

代码语言:javascript
复制
double scores[N_OF_TEAMS];

要读取这些值,可以使用:

代码语言:javascript
复制
int read_name_and_score( char * fname, int m, char nn[][MAX_CHAR_IN_NAME], double * ss)
{
    FILE *pf;
    int count = 0;

    if (!fname) {
        prinf("Error, no file name.\n");
        return -1;
    }
    pf = fopen(fname,'r');
    if (!pf) {
        printf("An error occurred while opening file %s.\n",fname);
        return -2;
    }

    while ( count < m && fscanf(pf, "%[^,],%d\n", nn[count], &ss[count]) == 2 ) count++;

    if (!fclose(pf)) {
        printf("An error occurred while closing file %s.\n",fname);
    };
    return count;
}

如果需要^,以便在找到a时停止扫描字符串,主要内容将如下所示:

代码语言:javascript
复制
#define N_OF_TEAMS 32
#define MAX_CHAR_IN_NAME 30

int main(void) {
    char team_names[N_OF_TEAMS][MAX_CHAR_IN_NAME];
    double scores[N_OF_TEAMS];
    int n;

    n = read_name_and_score("data.csv",N_OF_TEAMS,team_names,scores);
    if ( n != N_OF_TEAMS) {
        printf("Error, not enough data was read.\n");
        /* It's up to you to decide what to do now */
    }

    /* do whatever you want with data */

    return 0;
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33761409

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档