【问题标题】:Incorrect results after scanning a file using fscanf使用 fscanf 扫描文件后结果不正确
【发布时间】:2020-10-24 22:19:12
【问题描述】:

我在使用fscanf 扫描.txt 文件中的一些数据时遇到问题。

例子:

CXKNS87356 John March 136 - Mary Perpetum 419; 8.2.2014. 05:42 3.80257 71.45

typedef struct
{
        char code[12];
        char from[45];
        char to[45];
        int day;
        int month;
        int year;
        int hour;
        int min;
        float km;
        float price;
    
}Taxi;

while(fscanf(fin, "%[^ \n]%[^-]-%[^;]; %d.%d.", taxi[i].code, taxi[i].from, taxi[i].to, &taxi[i].day, &taxi[i].month)==5)
{
        printf("|%s| |%s| |%s| |%d| ", taxi[i].code, taxi[i].from, taxi[i].to, taxi[i].day);
        i++;
}

使用此代码,我可以fscanf 直到我输入&taxi[i].month,从那里代码不起作用。我需要正确上传示例

【问题讨论】:

  • %[^-] - 匹配多少字符串?
  • 我不明白,它会上传第一个地址的字符串(来自)直到 -
  • 但我仍然需要 %d.%d.,问题在于点
  • 这只是一行代码,需要添加到已接受的答案中以删除最后一个不需要的空间。见下文。

标签: c file scanf


【解决方案1】:

你想要例如:

  char restofline[64];
  ...
  while(fscanf(fin, " %11[^ ]%44[^-]-%[^;]; %d.%d.%63[^\n]", taxi[i].code, taxi[i].from, taxi[i].to,
             &taxi[i].day, &taxi[i].month, restofline)==6)

因为您需要刷新行的其余部分 scanf 不在您的代码中管理

注意第一个 '%' 之前的空格以绕过前一行的换行符,事实上我限制了要读取的字符串的大小以不写出数组

例如:

#include <stdio.h>

typedef struct{
    char code[12];
    char from[45];
    char to[45];
    int day;
    int month;
    int year;
    int hour;
    int min;
    float km;
    float price;

}Taxi;

int main()
{
  int i = 0;
  Taxi taxi[10];
  char restofline[64];
  
  while(fscanf(stdin, " %11[^ ]%44[^-]-%[^;]; %d.%d.%63[^\n]", taxi[i].code, taxi[i].from, taxi[i].to,
               &taxi[i].day, &taxi[i].month, restofline)==6)
  {
    printf("|%s| |%s| |%s| |%d| \n", taxi[i].code, taxi[i].from, taxi[i].to, taxi[i].day);
    if (++i == 10)
      break;
  }
  
  return 0;
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -Wall c.c
pi@raspberrypi:/tmp $ ./a.out
CXKNS87356 John March 136 - Mary Perpetum 419; 8.2.2014. 05:42 3.80257 71.45
|CXKNS87356| | John March 136 | | Mary Perpetum 419| |8| 
CXKNS87356 John March 136 - Mary Perpetum 419; 8.2.2014. 05:42 3.80257 71.45
|CXKNS87356| | John March 136 | | Mary Perpetum 419| |8| 
^C
pi@raspberrypi:/tmp $ 

如果你想保存所有字段:

#include <stdio.h>

typedef struct{
    char code[12];
    char from[45];
    char to[45];
    int day;
    int month;
    int year;
    int hour;
    int min;
    float km;
    float price;

}Taxi;

int main()
{
  int i = 0;
  Taxi taxi[10];
  
  while(fscanf(stdin, " %11[^ ] %44[^-]- %[^;]; %d.%d.%d.%d:%d%f%f",
               taxi[i].code, taxi[i].from, taxi[i].to,
               &taxi[i].day, &taxi[i].month, &taxi[i].year, 
               &taxi[i].hour, &taxi[i].min,
               &taxi[i].km, &taxi[i].price)==10)
  {
    printf("|%s| |%s| |%s| |%d| %d:%d %f %f\n",
           taxi[i].code, taxi[i].from, taxi[i].to, taxi[i].day,
           taxi[i].hour, taxi[i].min, taxi[i].km, taxi[i].price);
    if (++i == 10)
      break;
  }
  
  return 0;
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -Wall c.c
pi@raspberrypi:/tmp $ ./a.out
CXKNS87356 John March 136 - Mary Perpetum 419; 8.2.2014. 05:42 3.80257 71.45
|CXKNS87356| |John March 136 | |Mary Perpetum 419| |8| 5:42 3.802570 71.449997
CXKNS87356 John March 136 - Mary Perpetum 419; 8.2.2014. 05:42 3.80257 71.45
|CXKNS87356| |John March 136 | |Mary Perpetum 419| |8| 5:42 3.802570 71.449997
^C
pi@raspberrypi:/tmp $ 

remark 在第一个 '%' 之前仍然存在的空格以绕过换行符从一行到下一行。我还在字段“to”的开头添加了一个以刷新空格,但您需要删除字段“from”和“to”末尾的可能空格

【讨论】:

  • 为什么我这样做会起作用:while(fscanf(fin, " %[^ \n]%[^-]-%[^;]; %d.", tax[i] .code,taxi[i].from,taxi[i].to,&taxi[i].day)==4) { 如果我在上面写代码(我写的)它不起作用
  • @Momo 如果您想获得该行的正确部分来读取其中的几个,您需要阅读行尾以刷新它,请查看我的答案中的执行,同时解释兴趣第一个'%'之前的空格
  • %[^\n] %[^-] - %[^;]; %d.%d.%d. %d:%d %f %[^\n],这个完整的 fscanf 不起作用(我在最后上传浮动价格)
  • 不要像我在回答中那样以"%[^\n] 开头,而是以" %[^ ] 开头,不要在第一个“%..”中使用\n,但只能在最后一个,但是当最后一个字段不是字符串,甚至不要在最后一个字段中使用'\n'
  • 布鲁诺杰西蒂纳斯
【解决方案2】:

您错过了不想读入的字符

$ grep scanf test2.c 
fscanf(stdin, "%[^ \n] %[^-] - %[^;]; %d.%d.", taxi[i].code, taxi[i].from, taxi[i].to, &taxi[i].day, &taxi[i].month);
$ echo 'CXKNS87356 John March 136 - Mary Perpetum 419; 8.2.2014. 05:42 3.80257 71.45'|./test2
|CXKNS87356| |John March 136 | |Mary Perpetum 419| |8| 

| |和 | |之后 |-|失踪了。 示例:您的第一个匹配项是%[^ \n],它不包括空格,但您没有在之后添加被排除的空格。添加空格,然后您的下一场比赛%[^-] 将会发生。之后使用 |- | (连字符后有空格)。

这样做的唯一缺点是 John 的尾随空格。

如何区分“John 字段”中的空格是属于该字段还是分隔符?我认为 scanf 解析器无法处理。正则表达式可以。或者你修复from 的结尾,例如:

$ grep strlen test2.c 
if (taxi[i].from[strlen(taxi[i].from)-1] == ' ') taxi[i].from[strlen(taxi[i].from)-1] = 0;

$ echo 'CXKNS87356 John March 136 - Mary Perpetum 419; 8.2.2014. 05:42 3.80257 71.45'|./test2
|CXKNS87356| |John March 136| |Mary Perpetum 419| |8| 

通过这样做,您只需删除“John 字段”中的尾随空格。

这是我完整的 main() 方法:

int main() {
  Taxi taxi[1];
  int i=0;
  // 'CXKNS87356 John March 136 - Mary Perpetum 419; 8.2.2014. 05:42 3.80257 71.45'
  fscanf(stdin, "%[^ \n] %[^-] - %[^;]; %d.%d.", taxi[i].code, taxi[i].from, taxi[i].to, &taxi[i].day, &taxi[i].month);
  if (taxi[i].from[strlen(taxi[i].from)-1] == ' ') taxi[i].from[strlen(taxi[i].from)-1] = 0;
  printf("|%s| |%s| |%s| |%d| \n", taxi[i].code, taxi[i].from, taxi[i].to, taxi[i].day);
  return 0;
}

字符串

CXKNS87356 John March 136 - Mary Perpetum 419; 8.2.2014. 05:42 3.80257 71.45

我只是从上面复制的。

注意:我像你一样忽略了年份、小时等等。我假设您将添加对它们的解析。

这意味着你的第一个 scanf 将解析直到

CXKNS87356 John March 136 - Mary Perpetum 419; 8.2.

你的下一个循环将继续解析

2014. 05:42 3.80257 71.45\n...

如果您不想解析年份和之后的所有内容,只需将其作为字符串解析到缓冲区中并忽略缓冲区的内容。

我认为您的解析丢失了,因为您解析了一个月,但只打印了一天。因此,它看起来正在进行中,问题出在空间上。

【讨论】:

  • I fscanf John 136 年 3 月(直到 -)
  • @Momo:你要和你的 cmets 一起禁食。 ;-) 我什至在打字,最后在 John 处修正了尾随空格。 :-)
  • 我的代码还是不行 xD, "(SPACE)%[^]%[^-]-%[^;]; %d.%d.%d. %d:% d %f %f"
  • @Momo 我添加了一条注释。我刚刚修复了解析字符串一行。我假设您将为其余字段添加解析。否则解析器将在月点之后停止,并且在下一个循环中将从第一个输入中获取年份!
猜你喜欢
  • 2012-07-14
  • 1970-01-01
  • 1970-01-01
  • 2012-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-28
  • 2016-05-04
相关资源
最近更新 更多