使用 fscanf 扫描文件后结果不正确

Incorrect results after scanning a file using fscanf

我在使用 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,从那里代码不起作用。我需要正确上传示例

你想要例如:

  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 未在您的代码中管理

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

例如:

#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 $ 

请注意 space 仍然存在于第一个 '%' 之前以绕过从一行到下一行的换行符。我还加了一个flush space(s)在字段'to'的开头,但是你需要去掉字段末尾可能的space(s)[=33] =] 和 'to'

你漏掉了不想读的字符:

$ 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],它排除了 space,但您没有在之后添加被排除的 space。添加 space 然后你的下一场比赛 %[^-] 就会发生。之后使用 |- | (连字符后有 space)。

这样做的唯一缺点是约翰尾随 space。

如何区分“约翰字段”中的space是属于该字段还是分隔符?我不认为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 field”中的尾随 space。

这是我完整的 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...

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

我假设你的解析丢失了,因为你最多解析了一个月,但只打印了一天。因此,看起来工作正在进行中,问题出在 spaces.