【问题标题】:How do I stop at a particular point in a file *stream and scan in some values?如何在文件 *stream 中的特定点停止并扫描某些值?
【发布时间】:2018-06-15 11:00:16
【问题描述】:

我有一个名为 test.txt 的文件,该文件包含:

<this is a test = 1>

<more tests = 42 and more "34">

<start>10.213123 41.21231 23.15323</start>

<random stuff = "4">

<blah 234>

当我看到&lt;start&gt; 时,我想将后面的 3 个数字扫描成这样的双精度数:

x = 10.213123
y = 41.21231
z = 23.15323

我有点困惑,因为 fgets 扫描整行,我如何将 3 个数字扫描成双精度数?因为数字可以有不同的长度?我这样做是为了打印出它从文件中读取的内容,但我无法理解它。

void  print_lines(FILE *stream) {
    char line[MAX_LINE_LENGTH];
    while (fgets(line, MAX_LINE_LENGTH, stream) != NULL) {
        fputs(line, stdout);
    }
}

【问题讨论】:

  • 这可能会有所帮助:How to read / parse input in C? The FAQ。特别是“阅读,然后解析”部分。您可以在代码中使用 fgets,然后使用 strtod 遍历该行。
  • 您可以创建一个函数来检查是否为line starts with "&lt;start&gt;",如果是则仅解析这一行。
  • 是否保证&lt;start&gt;&lt;/start&gt; 会在同一行?如果三个数字在两行或更多行上怎么办?如果您想处理这种情况,您将不得不使用不同的方法。

标签: c file while-loop double filestream


【解决方案1】:

当您看到&lt;start&gt; 时,将 3 个数字扫描成双精度数。您在line 变量中有行内容,您可以使用strtod 将字符串扫描成双精度。你甚至可以使用sscanf(line, "&lt;start&gt;%lf %lf %lf&lt;/start&gt;", &amp;x, &amp;y, &amp;z);,但使用strtod 更适合错误处理。

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>

#define MAX_LINE_LENGTH 1024

void  print_lines(FILE *stream) {
    double a, b, c;
    char line[MAX_LINE_LENGTH];
    while (fgets(line, MAX_LINE_LENGTH, stream) != NULL) {
        char *pnt;
        // locate substring `<start>` in the line
        if ((pnt = strstr(line, "<start>") != NULL)) {
            // advance pnt to point to the characters after the `<start>`
            pnt = &pnt[sizeof("<start>") - 1];
            char *pntend;

            // scan first number
            a = strtod(pnt, &pntend);
            if (pnt == pntend) {
                fprintf(stderr, "Error converting a value.\n");
                // well, handle error some better way than ignoring.
            }
            pnt = pntend;
            // scan second number
            b = strtod(pnt, &pntend);
            if (pnt == pntend) {
                fprintf(stderr, "Error converting a value.\n");
                // well, handle error some better way than ignoring.
            }
            pnt = pntend;
            // scan third number
            c = strtod(pnt, &pntend);
            if (pnt == pntend) {
                fprintf(stderr, "Error converting a value.\n");
                // well, handle error some better way than ignoring.
            }

            printf("Read values are %lf %lf %lf\n", a, b, c);
        } else {
            // normal line
            //fputs(line, stdout);
        }
    }
}

int main()
{
    print_lines(stdin);
    return 0;
}

【讨论】:

  • 我花了大约 10 分钟研究这段代码(我还在学习代码)。我只有2个问题。第一个是,我不明白“errno”是/做什么。第二个问题是,我知道你是如何使用 memcmp 来查找 的,但是如果 start 的位置是这样的&lt;start&gt;9.12 9 231.2&lt;/start&gt;(如果&lt;start&gt;hdf &lt;start&gt;9.12 9 231.2&lt;/start&gt;,前面有一堆空格。有没有办法具体找到了吗?
  • 1. errno 是,嗯,errno,你可以在网上阅读它(为什么它不好,为什么它好,为什么它仍然存在)。 strtod 在转换错误时将 errno 设置为 ERANGE。我想展示如何处理 strtod 转换错误。 2. 好吧,你决定你的程序支持什么格式。有许多标准功能可以帮助您。可能strstr(line, "<start>") 会有所帮助。
  • a = strtod(pnt, &amp;pnt); if (errno) { 不足以检测是否没有发生转换。 a = strtod(pnt, &amp;endptr); if (pnt == endptr) 确实如此。 strtod() 没有被 C 指定来设置 errno 不转换。
  • strtod()errno on underflow 令人讨厌地实现定义的行为
  • @KamilCuk 我阅读了strstr 函数。它找到所选字符串的第一次出现。如果没有找到,则返回 NULL,如果找到,则返回指针。但是,当我将 if (!memcmp(line, "&lt;start&gt;", sizeof("&lt;start&gt;")-1)) { 替换为 if (strstr(line, "&lt;start&gt;") != NULL) { 时,它不起作用。
猜你喜欢
  • 2021-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多