C Чтение файла цифр, разделенных запятыми - PullRequest
0 голосов
/ 22 марта 2019

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

Например: process.txt содержит

0,1,3
1,0,5
2,9,8
3,10,6

И массив чисел должен выглядеть так:

0 1 3 1 0 5 2 9 8 3 10 6

Код, который у меня был до сих пор:

FILE *fp1;
char c; //declaration of characters

fp1=fopen(argv[1],"r"); //opening the file



int list[300];


c=fgetc(fp1); //taking character from fp1 pointer or file
int i=0,number,num=0;

while(c!=EOF){ //iterate until end of file
    if (isdigit(c)){ //if it is digit
        sscanf(&c,"%d",&number); //changing character to number (c)
        num=(num*10)+number;

    }
    else if (c==',' || c=='\n') { //if it is new line or ,then it will store the number in list
        list[i]=num;
        num=0;
        i++;

    }

    c=fgetc(fp1);

}

Но возникают проблемы, если это двузначная цифра. У кого-нибудь есть лучшее решение? Спасибо!

Ответы [ 3 ]

2 голосов
/ 22 марта 2019

Для данных, отображаемых без пробелов перед запятыми, вы можете просто использовать:

while (fscanf(fp1, "%d,", &num) == 1 && i < 300)
    list[i++] = num;

Это будет читать запятую после числа, если оно есть, молча игнорируя, когда его нет. Если перед запятыми в данных может быть пробел, добавьте пробел перед запятой в строке формата. Тест на i запрещает вам писать за пределами массива list. Оператор ++ вступает в свои права здесь.

0 голосов
/ 22 марта 2019

Мое решение - сначала прочитать всю строку, а затем разобрать ее с помощью strtok_r с запятой в качестве разделителя. Если вы хотите переносимый код, используйте вместо него strtok.

Наивная реализация readline будет выглядеть примерно так:

static char *readline(FILE *file)
{
    char *line = malloc(sizeof(char));
    int index = 0;
    int c = fgetc(file);
    if (c == EOF) {
        free(line);
        return NULL;
    }
    while (c != EOF && c != '\n') {
        line[index++] = c;
        char *l = realloc(line, (index + 1) * sizeof(char));
        if (l == NULL) {
            free(line);
            return NULL;
        }
        line = l;
        c = fgetc(file);
    }
    line[index] = '\0';
    return line;
}

Тогда вам просто нужно проанализировать всю строку с помощью strtok_r, чтобы вы могли закончить что-то вроде этого:

int main(int argc, char **argv)
{
    FILE *file = fopen(argv[1], "re");
    int list[300];
    if (file == NULL) {
        return 1;
    }
    char *line;
    int numc = 0;
    while((line = readline(file)) != NULL) {
        char *saveptr;
        // Get the first token
        char *tok = strtok_r(line, ",", &saveptr);
        // Now start parsing the whole line
        while (tok != NULL) {
            // Convert the token to a long if possible
            long num = strtol(tok, NULL, 0);
            if (errno != 0) {
                // Handle no value conversion
                // ...
                // ...
            }
            list[numc++] = (int) num;
            // Get next token
            tok = strtok_r(NULL, ",", &saveptr);
        }
        free(line);
    }
    fclose(file);
    return 0;
}

А для печати всего списка просто используйте цикл for:

for (int i = 0; i < numc; i++) {
    printf("%d ", list[i]);
}
printf("\n");
0 голосов
/ 22 марта 2019

Во-первых, fgetc возвращает int, поэтому c должно быть int.

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

int c=fgetc(f);

while(c!=EOF && i<300) {
    if(isdigit(c)) {
        fseek(f, -1, SEEK_CUR);
        if(fscanf(f, "%d", &list[i++]) != 1) {
            // Handle error
        }
    }
    c=fgetc(f);
}

Здесь меня не интересуют запятые и переводы строк.Я беру НИЧЕГО кроме цифры в качестве разделителя.В основном я делаю следующее:

read next byte
if byte is digit:
     back one byte in the file
     read number, irregardless of length
else continue

Дополнительное условие i<300 по соображениям безопасности.Если вы действительно хотите проверить это, кроме запятых и новых строк (у меня не сложилось впечатление, что вы считаете это важным), вы можете легко добавить else if (c == ... для обработки ошибки.

Обратите внимание, что вам следуетвсегда проверяйте возвращаемое значение для таких функций, как sscanf, fscanf, scanf и т. д. На самом деле, вы также должны делать это для fseek.В этой ситуации это не так важно, так как этот код вряд ли потерпит неудачу по этой причине, поэтому я оставил его для удобства чтения.Но в рабочем коде вы ДОЛЖНЫ проверить это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...