чтение нескольких типов переменных из одной строки в файле C

Хорошо, я был в этом весь день и не могу за жизнь мне это записать, может быть, вы, ребята, можете помочь. У меня есть файл, который читается следующим образом

1301,105515018,"Боцман","Майкл Р.",ABC, 123,="R01"

1301,103993269,"Кастилия","Майкл младший",ABC, 123,="R03"

1301,103993267,"Кастилия","Дженис",ABC, 123,="R03"

1301,104727546,"Бончек","Клод",ABC, 123,="R01"

1301,104731479,"Круз","Аким Майк",ABC, 123,="R01"

1301,105415888,"Дигиакомо","Стивен",ABC, 123,="R02"

1301,106034479,"Аннитто Грасси","Сьюзен",ABC, 123,="R04"

1301,106034459, "Алс", "Христианин", ABC, 123, = "R01"

И вот мой код...

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

#define MAX_NAME 15
#define MAX_SUBSEC 3
#define N 128

//void printArr(struct *students);

struct student{

int term;
int id;
char lastname[MAX_NAME];
char firstname[MAX_NAME];
char subjectname[MAX_SUBSEC];
int catalog;
char section[MAX_SUBSEC];

}students[10];

int main(){

int term;
int id;
char lastname[MAX_NAME];
char firstname[MAX_NAME];
char sub[MAX_SUBSEC];
int cat;
char sec[MAX_SUBSEC];

char fname[N];
FILE *inputf;

printf("Enter the name of the text file: ");
scanf("%123s",fname);

strcat(fname,".txt");

inputf = fopen(fname,"r");

if (inputf == NULL){

     printf("I couldn't open the file for reading.\n");
     exit(0);

}
//TROUBLE HERE!

fscanf(inputf, "%d,%d,%[^,]s", &students[0].term, &students[0].id,students[0].lastname);

printf("%d\n", students[0].term);

printf("%d\n", students[0].id);

printf("%s\n", students[0].lastname);

/*for (j = 1 ; j <= 10-1 ; j++){

    for(k = 0 ; k <= 10-2 ; k++){

        if(students[k] > students[k+1]){

            temp = students[k];
            students[k] = students[k+1];
            students[k+1] = temp;

            }
        }
    }*/

fclose(inputf);

system("pause");

return 0;

}

void printArr(int a[], int tally){

int i;

for(i = 0 ; i < tally ; i++){

 printf("%d ", a[i]);

}

printf("\n");

}

Моя цель - взять каждое из этих значений в текстовом файле и ввести его туда, где оно принадлежит в структуре, а затем в массиве структур, но я не могу передать первые 2 целых числа.

Получение строки фамилии, поскольку она состоит максимум из 15 символов, она переходит в строку имени сразу после нее и берет оставшиеся символы, необходимые для заполнения массива символов фамилии. Очевидно, я не хочу этого. Как вы можете видеть, я попробовал strtok, но он ничего не делает, хотя не уверен, что мне нужно делать, поскольку я никогда не использовал его раньше. Также попытался просто включить все переменные в оператор fscanf, но я либо получаю тот же результат, либо становится беспорядком. Как бы то ни было, я очень растерялся, как мне получить эти значения в переменных, которым они принадлежат?!

РЕДАКТИРОВАТЬ: обновил мой код, я продвинулся немного дальше, но не намного. Теперь я могу распечатать только фамилию, но не могу дальше, я не могу добраться до строки имени или какой-либо из переменных за ее пределами.


person Sherifftwinkie    schedule 01.03.2013    source источник
comment
Пожалуйста, не редактируйте свой вопрос, чтобы сделать ответы недействительными.   -  person Jonathan Leffler    schedule 22.07.2014


Ответы (5)


У вас есть файл CSV со строками в кавычках, поэтому я бы рекомендовал вам использовать парсер CSV (или свернуть свой собственный), а не пытаться сделать все это с помощью scanf (поскольку scanf не может работать с кавычками, например, запятыми в строках в кавычках ). Быстрый поиск в Google находит libcsv.c, который вы можете использовать в ваш проект.

person nneonneo    schedule 01.03.2013
comment
CSV-файл? О, это все просто в простом текстовом файле - person Sherifftwinkie; 01.03.2013
comment
... он разделен запятыми, содержит объекты в кавычках и что-то похожее на ссылки на уравнения Excel. Я называю это CSV. (расширение файла не имеет значения). - person nneonneo; 01.03.2013
comment
о, жаль, что я никогда не слышал этого раньше! - person Sherifftwinkie; 01.03.2013

С помощью строки формата fscanf "%d,%d,\"%[^\"]\",\"%[^\"]\",%[^,],%d,=\"%[^\"]\"" мы можем прочитать данные всей строки. Кроме того, вы должны определить

char lastname[MAX_NAME+1];
char firstname[MAX_NAME+1];
char subjectname[MAX_SUBSEC+1];
int catalog;
char section[MAX_SUBSEC+1];

+1 для учета завершающего символа '\0'.

person Armali    schedule 04.06.2014
comment
+1 - это только часть ответа, но я все равно дам вам +1. Вам нужно учитывать длину, чтобы предотвратить переполнение буфера; было бы лучше использовать %14[^\"], чтобы ограничить строку пространством, которое существует в структуре (14 равно MAX_NAME-1), вместо того, чтобы допускать дополнительный символ, который затем должен обрабатываться особым образом. - person Jonathan Leffler; 22.07.2014
comment
Мы должны объединить оба улучшения, используя %15[^\"], потому что 14 недостаточно для Annitto Grassis, и мне кажется более ясным думать о MAX_NAME как о максимальной длине имени. - person Armali; 22.07.2014
comment
Но тогда структура также должна использовать MAX_NAME+1. Длина, указанная в формате scanf(), не включает завершающий нуль. Но вы правы: Annitto Grassis требует 15 символов плюс нулевой байт. - person Jonathan Leffler; 22.07.2014

У меня к вам вопрос... Если вы хотите узнать, как пользоваться алмазным резаком, попробуйте и посмотрите сами или сверитесь с инструкцией? Проблема здесь не в результате вашего выбора, а в самом вашем выборе. Хотите верьте, хотите нет, но я так часто отвечал на эти вопросы, что устал повторяться. Все ответы есть в мануале.

Прочтите руководство по POSIX 2004 scanf или версия POSIX 2008/2013 — и ответ этот вопрос, и у вас будет некоторое представление о том, что вы не делать то, что вы должны быть. Даже код fscanf должен использовать assert в качестве средства отладки, чтобы убедиться, что количество прочитанных элементов было правильным.

%[^,]s Кажется, здесь ошибка. Возможно, вы имели в виду %[^,]. Спецификатор формата %[ отличается от спецификатора формата %s, поэтому в предположительно ошибочном коде есть две директивы: %[^,] и s. Директива s указывает scanf читать 's' и отбрасывать его.

person autistic    schedule 01.03.2013
comment
Я могу понять разочарование, выраженное первым абзацем, но это не совсем подходит для SO. Стоит указать на распространенную путаницу с наборами сканирования с s после них, а также на руководство (я дал обновление до самого последнего стандарта POSIX). Вы можете пометить этот комментарий на удаление (устаревший), когда прочитаете его и исправите свой ответ — я бы просто удалил первый абзац. - person Jonathan Leffler; 22.07.2014

1. Синтаксическая ошибка

while(result != NULL){

      printf(".....);

      ......

}

}//error
  1. fscanf(inputf, "%s", lastname); не может прочитать строку, fscanf остановится, когда наткнется на пробел
person goingstudy    schedule 01.03.2013

fscanf считывает по одной строке за раз, и вы можете легко захватить содержимое каждой строки, потому что ваш файл довольно хорошо отформатирован, особенно из-за разделения запятыми (действительно полезно, если ни одно из ваших разделенных значений не содержит запятую).

Вы можете передать fscanf формат, как вы делаете с "%d" для захвата int, "%s" для захвата строки (оканчивающейся пробелом, будьте осторожны с этим, когда, например, пытаетесь найти имя, такое как "Annitto Grassis, для чего потребуется 2 %s) и т. д. из текущей строки файла. Вы можете быть более продвинутым и использовать шаблоны регулярных выражений для определения содержимого, которое вы хотите захватить в виде символов, например «Боцман», последовательность, состоящая из символов из наборов {AZ}, {az} и {"}. Вы захотите сканировать файл, пока не дойдете до конца (обозначенного EOF в C), чтобы вы могли сделать это и захватить содержимое строки и соответствующим образом присвоить значения переменным следующим образом:

while( fscanf(inputf, "%d,%d,%[\"A-Za-z ],%[\"A-Za-z .]", &term, &id, фамилия, имя) != EOF) {

.... // сделать что-то с термином, идентификатором, фамилией, именем - поместить их в структуру ученика

}

Дополнительные сведения о регулярных выражениях можно найти в Mastering Regex Джеффа Фридла, которая является хорошей книгой для изучения этой темы.

person dpflan    schedule 01.03.2013
comment
Использование регулярных выражений является излишним, когда у OP возникают основные проблемы с программированием на C. - person Jonathan Leffler; 22.07.2014