fscanf для текстовых файлов в C - PullRequest
1 голос
/ 08 июля 2020

У меня есть файл, в котором

1   Toy Story   1995    01-Jan-1995 http://us.imdb.com/M/title-exact?Toy%20Story%20(1995)   Animation|Children's|Comedy 
2   GoldenEye   1995    01-Jan-1995 http://us.imdb.com/M/title-exact?GoldenEye%20(1995) Action|Adventure|Thriller   

и пробел между столбцами записан с помощью табуляции, вот мой код, но ...

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <unistd.h>

FILE *MovieF;
void addFileM();

struct Movies
{
   char MID[50];
   char MName[50];
   char MYear[50];
   char MDate[50];
   char MIMDB[100];
   char MGen[100];
}Movie[100];


int main()
{
    addFileM();
    return 0;
}


void addFileM()
{
    MovieF = fopen("d:\\movies.txt","r");
    for(int i=0;i<60;i++)
    {
        fscanf(MovieF, "%s\t%s\t%s\t%s\t%s\t%s\n",Movie[i].MID,Movie[i].MName,Movie[i].MYear,Movie[i].MDate,Movie[i].MIMDB,Movie[i].MGen);
    }
    for(int i=0;i<60;i++)
    {
        printf("%s\n%s\n%s\n%s\n%s\n%s\n\n",
                Movie[i].MID, Movie[i].MName, Movie[i].MYear,
                Movie[i].MDate, Movie[i].MIMDB, Movie[i].MGen);
    }
}

и вывод:

1
Toy
Story
1995
01-Jan-1995
http://us.imdb.com/M/title-exact?Toy%20Story%20(1995)

Animation|Children's|Comedy
2
GoldenEye
1995
01-Jan-1995
http://us.imdb.com/M/title-exact?GoldenEye%20(1995)

Action|Adventure|Thriller
3
Four
Rooms
1995
01-Jan-1995

Как видите, «История игрушек» хранится в двух разных полях, и данные жанра первого mov ie печатаются вместе со вторым mov ie.

Вы можете мне сказать в чем проблема?

1 Ответ

0 голосов
/ 09 июля 2020

Проблема в том, что спецификатор формата %s останавливает сканирование всякий раз, когда обнаруживается whitespece char (пробел, табуляция, новая строка и т. Д.).

Вот почему оба «История игрушек» и «Четыре комнаты» хранятся в двух разных полях вашей структуры, что заставляет сканирование буквально «сдвигать» позиции (поле жанра первого mov ie будет стать первым полем второго mov ie и так далее).

Вместо %s вы можете использовать %[^\t].

Квадратные скобки спецификатор формата просматривает строку, содержащую набор символов. Но если присутствует ^, содержащийся символ избегается. Таким образом, в данном случае это означает "сохранить строку и останавливаться при обнаружении первой вкладки" .

Еще лучше: вы можете сохранить не более N символов, используя формат %N[^\t]. Учитывая размер вашего целевого массива, просто укажите N как этот размер минус один (оставив место для терминатора строки).

Ваш fscanf станет примерно таким:

fscanf(MovieF, "%49[^\t]%49[^\t]%49[^\t]%99[^\t]%99[^\t]\n",
       Movie[i].MID, Movie[i].MName, Movie[i].MYear,
       Movie[i].MDate, Movie[i].MIMDB, Movie[i].MGen);
...