简体   繁体   English

如何仅将 txt 文件中的整数值读入数组?

[英]How can I read only the integer values from a txt file into an array?

I am modifying some existing code I wrote to take in resistance and current values from a .txt file and calculate the voltage solutions.我正在修改我编写的一些现有代码,以从.txt文件中获取电阻和电流值并计算电压解决方案。 What has me stumped is that once I read a line in and use strtok to separate the integers from the other text, I don't know how to properly save those values to some variables that I can then plug into an array.让我感到困惑的是,一旦我读入一行并使用strtok将整数与其他文本分开,我不知道如何将这些值正确保存到某些变量中,然后我可以将其插入数组。

Here is an example line that is read in from the text file:这是从文本文件中读入的示例行:

R3:56.0, R1:33.0, R2:47.0, R4:68.0, R5:75.0, IA:10.0, IB:110.0 R3:56.0, R1:33.0, R2:47.0, R4:68.0, R5:75.0, IA:10.0, IB:110.0

My code below takes that line and outputs:我下面的代码采用该行并输出:

R3
56.0
 R1
33.0
 R2
47.0
 R4
68.0
 R5
75.0
 IA
10.0
 IB
110.0

My next goal would be to somehow identify R3 = 56.0 and R1 = 33.0 and so on, storing these values into variables named R1 , R2 , R3 , R4 , R5 , I1 , I2 so that I can use them later in my code.我的下一个目标是以某种方式识别R3 = 56.0R1 = 33.0等等,将这些值存储到名为R1R2R3R4R5I1I2变量中,以便我稍后可以在我的代码中使用它们。

#include <stdio.h>
#include <string.h>

#define LINEMAX 100

int main()
{
    FILE *dataPtr;
    char line[LINEMAX];
    char* token;
    float R1 ,R2, R3, R4, R5, I1, I2;
    double A[4][5];
    int i = 0;

    if((dataPtr = fopen("input.txt" , "r")) == NULL)
    {
        fprintf(stderr , "FILE NOT FOUND!");
    }

    while (fgets(line, LINEMAX, dataPtr) != NULL)
    {
        token = strtok (line, ",:");
        while (token != NULL)
        {
            printf("%s\n" , token);
            token = strtok (NULL, ",:");
        }
    }
    fclose(dataPtr);

Here are a couple of suggestions to help you along parsing each line into the values you need.这里有一些建议可以帮助您将每一行解析为您需要的值。 Rather than 7 separate variables, R1, R2, R3, R4, R5, I1, I2 , just declare an array of double (using float just introduces more rounding error, and doesn't really buy any great savings in speed on modern processors).而不是 7 个单独的变量, R1, R2, R3, R4, R5, I1, I2 ,只需声明一个double数组(使用float只会引入更多的舍入误差,并且并没有真正节省现代处理器的速度) . Store your values in order in the array (eg R1 at index 0 , R2 at index 1 , and so on). (例如存储你的值,以便在阵列中R1在索引0R2在索引1 ,依此类推)。 That way if you have multiple lines of the same data, it's just a matter of filling a temporary array of 7 elements and a memcpy to an array of them.这样,如果您有多行相同的数据,只需将 7 个元素的临时数组和一个memcpy填充到它们的数组中即可。

You have done a good job using a #define for LINEMAX to avoid sprinkling Magic-Numbers throughout your code.您已经很好地使用了LINEMAX#define来避免在整个代码中散布魔术数字 You can do the same thing for string constants as well, eg你也可以对字符串常量做同样的事情,例如

#define MAXC 1024       /* if you need a constant, #define one (or more) */
#define TOKLEN 32       /* size for temporary token storage */
#define NELEM   7       /* number of elements to separate (R1-5, IA, IB) */
#define DELIM ",\n"     /* delimiter for strtok */

In parsing your line of data, you will need to map strings like "R1" to indexes and need a way to map indexes to strings (so you can do the reverse).在解析您的数据行时,您需要将诸如"R1"类的字符串映射到索引,并且需要一种将索引映射到字符串的方法(因此您可以反向操作)。 A handy way when the number of mappings is small like here is just to use an enum and an array-of-pointers to string literals, eg当映射数量很少时,像这里这样的一个方便的方法就是使用enum指针数组来字符串文字,例如

/* enum for mapping names to index */
enum { R1, R2, R3, R4, R5, IA, IB };
/* array for mapping index to names */
const char *id[] = { "R1", "R2", "R3", "R4", "R5", "IA", "IB" };

It is just another way to avoid sprinkling string literals throughout your code as well as providing a mapping that let's you avoid, eg这只是避免在整个代码中散布字符串文字以及提供让您避免的映射的另一种方法,例如

            if (strcmp (tmp, "R1") == 0)
                a[R1] = d;
            else if (strcmp (tmp, "R2") == 0)
                a[R2] = d;
            ...

And, instead use the following which leaves your single definition of id at the top as the only place you have to change the string mappings should they change in the future, eg并且,改为使用以下内容,将id的单一定义保留在顶部,作为将来更改字符串映射时必须更改的唯一位置,例如

            if (strcmp (tmp, id[R1]) == 0)
                a[R1] = d;
            else if (strcmp (tmp, id[R2]) == 0)
                a[R2] = d;
            ...

For the parsing of values into the respective array indexes, you would simply read each line into your buffer, tokenize the line with strtok to obtain the comma-separated-values, and then use sscanf on the tokens to parse the name and value from each token, eg为了将值解析为相应的数组索引,您只需将每一行读入缓冲区,用strtok标记该行以获得逗号分隔值,然后在标记上使用sscanf来解析每个行的名称和值令牌,例如

int main (int argc, char **argv) {

    char buf[MAXC];     /* buffer to hold each line */
    ...
    while (fgets (buf, MAXC, fp)) { /* read each line into buf */
        char tmp[TOKLEN];           /* temporary storage for R3, etc.. */
        double d, a[NELEM] = {0.};  /* temporary double and array */
        /* tokenize line */
        for (char *p = strtok(buf, DELIM); p; p = strtok(NULL, DELIM)) {
            /* separate token into tmp string and double value in array */
            if (sscanf (p, " %31[^:]:%lf", tmp, &d) != 2) {
                fputs ("error: bad token format\n", stderr);
                goto nextline;  /* goto steps over code to process full arr */
            }
            ... /* compare tmp value here and store in-order in array */
        }
        ... /* handle whatever additional processing on array needed here */
        nextline:;      /* label for nextline */
    }

( note: the a[NELEM] = {0.}; array is initialized all zero so if for some reason a line is missing a value, you don't invoke undefined behavior attempting to access an uninitialized value) 注意: a[NELEM] = {0.};数组初始化为零,因此如果由于某种原因一行缺少值,则不会调用未定义的行为尝试访问未初始化的值)

Where above the /* compare tmp value ... */ logic would simply be: /* compare tmp value ... */逻辑上面的位置就是:

            /* compare value in tmp store in-order in array */
            if (strcmp (tmp, id[R1]) == 0)
                a[R1] = d;
            else if (strcmp (tmp, id[R2]) == 0)
                a[R2] = d;
            else if (strcmp (tmp, id[R3]) == 0)
                a[R3] = d;
            else if (strcmp (tmp, id[R4]) == 0)
                a[R4] = d;
            else if (strcmp (tmp, id[R5]) == 0)
                a[R5] = d;
            else if (strcmp (tmp, id[IA]) == 0)
                a[IA] = d;
            else if (strcmp (tmp, id[IB]) == 0)
                a[IB] = d;
            else {
                fputs ("error: unrecognized format.\n", stderr);
                goto nextline;
            }

And for the further processing, for the example we simply output the values in order, eg对于进一步的处理,例如我们只是按顺序输出值,例如

        for (int i = 0; i < NELEM; i++) /* output line results */
            printf ("got %s = %.2f\n", id[i], a[i]);

A short example that takes your line of input and fully separates the double values into an array in-order of R1-5, IA, IB would be:一个简短的示例,它采用您的输入行并将双R1-5, IA, IB值按R1-5, IA, IB的顺序完全分离到一个数组中:

#include <stdio.h>
#include <string.h>

#define MAXC 1024       /* if you need a constant, #define one (or more) */
#define TOKLEN 32       /* size for temporary token storage */
#define NELEM   7       /* number of elements to separate (R1-5, IA, IB) */
#define DELIM ",\n"     /* delimiter for strtok */

/* enum for mapping names to index */
enum { R1, R2, R3, R4, R5, IA, IB };
/* array for mapping index to names */
const char *id[] = { "R1", "R2", "R3", "R4", "R5", "IA", "IB" };

int main (int argc, char **argv) {

    char buf[MAXC];     /* buffer to hold each line */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    while (fgets (buf, MAXC, fp)) { /* read each line into buf */
        char tmp[TOKLEN];           /* temporary storage for R3, etc.. */
        double d, a[NELEM] = {0.};  /* temporary double and array */
        /* tokenize line */
        for (char *p = strtok(buf, DELIM); p; p = strtok(NULL, DELIM)) {
            /* separate token into tmp string and double value in array */
            if (sscanf (p, " %31[^:]:%lf", tmp, &d) != 2) {
                fputs ("error: bad token format\n", stderr);
                goto nextline;  /* goto steps over code to process full arr */
            }
            /* compare value in tmp store in-order in array */
            if (strcmp (tmp, id[R1]) == 0)
                a[R1] = d;
            else if (strcmp (tmp, id[R2]) == 0)
                a[R2] = d;
            else if (strcmp (tmp, id[R3]) == 0)
                a[R3] = d;
            else if (strcmp (tmp, id[R4]) == 0)
                a[R4] = d;
            else if (strcmp (tmp, id[R5]) == 0)
                a[R5] = d;
            else if (strcmp (tmp, id[IA]) == 0)
                a[IA] = d;
            else if (strcmp (tmp, id[IB]) == 0)
                a[IB] = d;
            else {
                fputs ("error: unrecognized format.\n", stderr);
                goto nextline;
            }
        }
        for (int i = 0; i < NELEM; i++) /* output line results */
            printf ("got %s = %.2f\n", id[i], a[i]);

        nextline:;      /* label for nextline */
    }

    if (fp != stdin)    /* close file if not stdin */
        fclose (fp);

    return 0;
}

Example Use/Output示例使用/输出

Using your line of input in the file dat/rnumval.txt , you would receive:使用文件dat/rnumval.txt的输入行,您将收到:

$ ./bin/readrnumval dat/rnumval.txt
got R1 = 33.00
got R2 = 47.00
got R3 = 56.00
got R4 = 68.00
got R5 = 75.00
got IA = 10.00
got IB = 110.00

Which is just one way of conveniently mapping the separate values into identifiable indexes within the array allowing you to map names and indexes.这只是方便地将单独的值映射到数组中的可识别索引的一种方式,允许您映射名称和索引。 (which is why I would recommend leaving your names and literals matching with the data in your input, eg IA, IB instead of I1, I2 -- up to you, just more work) (这就是为什么我建议将您的姓名和文字与输入中的数据保持匹配,例如IA, IB而不是I1, I2由您决定,只需更多工作)

Look things over and let me know if you have further questions.仔细检查一下,如果您还有其他问题,请告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM