Как прочитать специфические c символов и целых из файла (вопрос об обновлении)? - PullRequest
0 голосов
/ 09 марта 2020

У меня есть входной файл:

H
3(3,3)
V
1(5,4)
2(7,7)

Я читаю это с:

 12 FILE *fp = fopen (argv[1], "r");
 13   if (fp == NULL)
 14   {
 15     return EXIT_FAILURE;
 16   }
 17   Stack* top = NULL;
 18   char gets[1024];
 19   while (fgets (gets, 1024, fp))
 20   {
 21     char node;
 22     int width = 0;
 23     int height = 0;
 24     int check = (sscanf (gets, " %c(%d,%d", &node, &width, &height));
 25     if (check == 1)
 26     {
 27       push(&top,node,0,0);
 28     }
 29     else if (check == 3)
 30     {
 31        push(&top,node,width,height);
 32     }
 33   }
 34   fclose (fp);

Что отлично работает.

  1 3(3,3)
  2 1(5,4)
  3 2(7,7)
  4 V
  5 H

Но когда я читаю что-то вроде этого (ввод сокращен, поскольку файл большой):

  1 93(11,16)
  2 11(12,33)
  3 H
  4 34(7,11)
  5 10(9,27)
  6 V
  7 32(12,30)
  8 30(12,16)
  9 41(12,19)
 10 H
 11 V
 12 50(12,13)

Я получаю это, например:

  1 9(0,0)
  2 1(0,0)
  3 H
  4 3(0,0)
  5 1(0,0)
  6 V
  7 3(0,0)
  8 3(0,0)
  9 4(0,0)
 10 H
 11 V
 12 5(0,0)

Как я могу исправить эту ошибку, чтобы поставить правильный вывод - поэтому я получаю правильное значение узла вместо 9 например вместо 93. Изменить: Это не работает, я получаю что-то вроде этого:

20 45(11,16)
 21 45(11,16)
 22 45(11,16)
 23 45(11,16)
 24 45(11,16)
 25 45(11,16)
 26 45(11,16)
 27 45(11,16)
 28 45(11,16)
 29 45(11,16)
 30 45(11,16)
 31 45(11,16)
 32 45(11,16)
 33 45(11,16)
 34 45(11,16)
 35 45(11,16)
 36 45(11,16)
 37 45(11,16)
 38 45(11,16)
 39 45(11,16)
 40 45(11,16)
 41 45(11,16)
 42 45(11,16)
 43 45(11,16)
 44 45(11,16)
 45 45(11,16)
 46 45(11,16)
 47 45(11,16)

, который даже не ввод.

Ответы [ 2 ]

1 голос
/ 09 марта 2020

В этой итерации вашего вопроса вместо того, чтобы иметь только один символ перед первым "(" или в отдельной строке, теперь вы можете иметь несколько символов. Вы по-прежнему хотите иметь возможность читать 'H' или 93 в качестве первой части строки, поэтому вам необходимо настроить format-string для чтения нескольких символов перед первым "(" и затем либо трактуйте это как строку, если это альфа-символ, либо преобразуйте его в целочисленные значения, если он состоит из цифр. Вы можете использовать что-то вроде:

#define MAXN   32
...
    while (fgets (buf, MAXC, fp)) {
        char tmp[MAXN];
        int node, width, height;
        switch (sscanf (buf, " %31[^(\n](%d,%d", tmp, &width, &height)) {
           ...

Строка формата " %31[^(\n](%d,%d", где '\n' включен в отрицательный класс символов вместе с '(', чтобы обрезать '\n' из тех строк, которые содержат только один символ. окружность (например, '^') в начале [^..], указывающая на то, что вы должны прочитать символ, не включая то, что содержится в классе символов. (например, прекратить чтение при обнаружении первого отрицательного символа)

Полный пример будет:

#include <stdio.h>

#define MAXC 1024   /* if you need a constant, #define one (or more) */
#define MAXN   32

int main (int argc, char **argv) {

    char buf[MAXC];
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    while (fgets (buf, MAXC, fp)) {
        char tmp[MAXN];
        int node, width, height;
        switch (sscanf (buf, " %31[^(\n](%d,%d", tmp, &width, &height)) {
            case 1 : printf ("single char/digit: '%s'\n", tmp);
                    break;
            case 3 : if (sscanf (tmp, "%d", &node) == 1)
                        printf ("all values: %d  %d  %d\n", node, width, height);
                    else
                        fputs ("error: parsing node from tmp.\n", stderr);
                    break;
            default : fputs ("invalid line format\n", stderr);
        }
    }
    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);
}

Вы можете изменить оператор switch() на свои операторы if/else.

Пример использования / вывода

С вашим обновленным вводом вы теперь получите:

$ ./bin/fgets_sscanf_multival2 dat/multivals2.txt
all values: 93  11  16
all values: 11  12  33
single char/digit: 'H'
all values: 34  7  11
all values: 10  9  27
single char/digit: 'V'
all values: 32  12  30
all values: 30  12  16
all values: 41  12  19
single char/digit: 'H'
single char/digit: 'V'
all values: 50  12  13

Где вы можете pu sh все значения для вашего стек, где это необходимо. Дайте мне знать, если у вас есть дополнительные вопросы.

1 голос
/ 09 марта 2020

Заменить int check = (sscanf (gets, " %c(%d,%d", &node, &width, &height)); и char node; на более сложные строки:

int node = 0;
int check = (sscanf (gets, "%d(%d,%d", &node, &width, &height));
if (check == 0)
{
  char n = 0;
  check = sscanf(gets, " %c", &n);
  node = n;
}
...