Сканируйте это из текстового файла в 2 массива, используя C - PullRequest
2 голосов
/ 20 февраля 2020

У меня проблемы с анализом чего-либо подобного в массив.

Итак, мой текстовый файл test.txt имеет следующую строку: (1231212A, 1231212B) (1231212 C, 321128D)

я пытаюсь отсканировать это в массив, но его нужно разделить на части

part1 типа int должно быть: 123

part2: 12

part3: 12

part4 (char): A

и мне нужно сделать это 4 раза в строке

Вот код, который у меня есть, но он не работает должным образом

{
int nums[1][12];
char chars[1][4];
FILE *file;

file = fopen("test.txt", "r");
if (file != NULL){

fscanf(file , "%*s%3d %2d %2d %s %*s %2d %2d %2d %s%*s        %*s%3d %2d %2d %s%*s %2d %2d %2d %s%*s" 
, &nums[0][0],&nums[0][1],&nums[0][2],&chars[0][0],&nums[0][3],&nums[0][4],&nums[0][5],&chars[0] 
[1],&nums[0][6],&nums[0][7],&nums[0][8],&chars[0][2],&nums[0][9],&chars[0][10],&nums[0][11],&chars[0] 
[3]);
}

когда я печатаю эти массивы, они не печатают правильные цифры и символы. Мне нужна помощь с fscanf. Спасибо

Ответы [ 2 ]

2 голосов
/ 20 февраля 2020

Как указал @chux в своем ответе, ключ правильно сопоставляет строку формата с данными, которые должны быть проанализированы, а затем критически проверяет возвращаемое значение по сравнению с ожидаемым числом преобразований. Основные ошибки в вашей строке формата - это ненужное включение %*s (чтобы попытаться пропустить "(") и %s %*s (чтобы попытаться пропустить запятую) и %s%*s %*s (чтобы попытаться и пропустите ") " в нескольких местах, что приведет к чтению чтения и отбрасыванию всего первого числа, например, "(1231212A," в виде строки, начало чтения значений во второй группе чисел и т. д.

Более точное совпадение, как показано в ответе @ chux, или просто:

"(%3d%2d%2d%c, %3d%2d%2d%c) (%3d%2d%2d%c, %3d%2d%2d%c"

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

Когда вы используете двумерный массив из 1 строки, в следующем упрощенном примере используется массив 1D для chars и nums, и его можно записать следующим образом: fgets(), передавая буфер в sscanf(), проверяя возвращаемый результат и выводя собранные значения или отображение ошибки в случае сбоя анализа:

#include <stdio.h>

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

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

    char buf[MAXC], chars[4];
    int nums[12];
    /* 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)) { /* read line into buf with fgets() */
        /* parse with sscanf -- validate 16 conversions take place */
        if (sscanf (buf, "(%3d%2d%2d%c, %3d%2d%2d%c) (%3d%2d%2d%c, %3d%2d%2d%c",
            &nums[0], &nums[1], &nums[2], &chars[0],
            &nums[3], &nums[4], &nums[5], &chars[1],
            &nums[6], &nums[7], &nums[8], &chars[2],
            &nums[9], &nums[10], &nums[11], &chars[3]) == 16) {
            /* output result */
            printf ("%d %d %2d %c\n%d %d %2d %c\n%d %d %2d %c\n%d %d %2d %c\n",
                    nums[0], nums[1], nums[2], chars[0],
                    nums[3], nums[4], nums[5], chars[1],
                    nums[6], nums[7], nums[8], chars[2],
                    nums[9], nums[10], nums[11], chars[3]);
        }   /* or handle error */
        else
            fprintf (stderr, "error parsing data from: %s\n", buf);
    }

    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);
}

Пример входного файла

$ cat dat/splitintoarr.txt
(1231212A, 1231212B) (1231212C, 321128D)

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

$ ./bin/splitintoarr <dat/splitintoarr.txt
123 12 12 A
123 12 12 B
123 12 12 C
321 12  8 D

(выходные данные последнего числа были выведены с использованием модификатора field-width , чтобы обеспечить выравнивание столбцов для ваших данных)

Просмотрите все ответы и дайте нам знать, если у вас есть дополнительные вопросы.

2 голосов
/ 20 февраля 2020

После прочтения строки из файла с fgets(), проанализируйте строку с sscanf(), включая "%n", чтобы определить, сколько было отсканировано.

Использование строкового литерала конкатенация в формате также помогает.

//                           v---not s
#define GROUP_FMT "%3d%2d%2d%c"

int n = 0;
sscanf(line, " (" GROUP_FMT " ," GROUP_FMT " ) (" GROUP_FMT " ," GROUP_FMT " ) %n",
  &nums[0][0], &nums[0][ 1], &nums[0][ 2], &chars[0][0], 
  &nums[0][3], &nums[0][ 4], &nums[0][ 5], &chars[0][1],
  &nums[0][6], &nums[0][ 7], &nums[0][ 8], &chars[0][2],
  &nums[0][9], &nums[0][10], &nums[0][11], &chars[0][3], &n);
// Did scanning reach the %n and was that the end of the string?
if (n && line[n] == '\0') Success();
else Fail();
...