Поиск элемента в файле и печать всей строки - PullRequest
0 голосов
/ 19 марта 2019

У меня есть файл с таким содержанием:

Code                Name     Income    Allow      Pens     Ins    Depend    Charity    Taxable       Tax       Net
------------------------------------------------------------------------------------------------------------------------
 008                John     100000     4000      5000    1000      3200       1000      85800     20280     79720
 001                 Doe      50000     4000         0     500      1600          0      43900      7725     42275

Я хочу напечатать запись, если введенный код совпадает с кодом в файле.
Это мой код:

fscanf(fp, " %3d%s%lf%lf%lf%lf%lf%lf%lf%lf%lf", &code_t, buffer, &inc_t, &personal, &pension_t, &health_t, &depend_t, &gift_t, &taxable_t, &tax_t, &net_t);  
printf("\n");
printf(" 03d%20s%11.0lf%9.0lf%10.0lf%8.0lf%10.0lf%11.0lf%11.0lf%10.0lf%10.0lf\n", code_t, buffer, inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t);
                `

но это не работает.
Поэтому я думаю об использовании fscanf для чтения только кода, а затем распечатки строки, содержащей этот код. Но как я могу прочитать код без другого содержимого, такого как Name, Income, ... и как читать, если код имеет начальный 0 как этот?

Ответы [ 2 ]

1 голос
/ 19 марта 2019

Сначала вы не можете прочитать файл с его заголовком, используя scanf , который вы даете, потому что Код несовместим с первым %d, поэтому вам нужно пропустить первые 2 строки

Предупреждение: % отсутствует в вашем printf для печати кода, поэтому код рассматривается как строка %s с неопределенным поведением (обычно сбой)

Но как я могу прочитать код без другого содержимого, такого как Имя, Доход

Конечно, если вы используете scanf , вы также читаете другие поля, еслиэто реальная проблема?Вы также можете прочитать строку за строкой как строки ( fgets или getline ) и посмотреть начало, если у вас есть ожидаемый код, и в этом случае управлять оставшейся частью строки для извлеченияполя при необходимости и т. д.

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

как читать, если код имеет начальный 0 как этот?

Я не понимаю scanf прочитайте это хорошо, это не восьмеричное, потому что есть 008. Если присутствие 0 слева важно, не управляйте кодом как числом, а как строкой как в файле, так и когда задан код для поиска


Ваш код хорошо читает ваш входной файл:

#include <stdio.h>

int bypassLine(FILE * fp)
{
  int c;

  for (;;) {
    c = fgetc(fp);

    if (c == EOF)
      return 0;
    if (c == '\n')
      return 1;
  }
}

int main()
{
  FILE * fp = stdin;
  int code_t;
  char buffer[64];
  double inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t;

  if (!bypassLine(fp) || !bypassLine(fp))
    puts("too short file");
  else {
    while (fscanf(fp, " %3d%s%lf%lf%lf%lf%lf%lf%lf%lf%lf", &code_t, buffer, &inc_t, &personal, &pension_t, &health_t, &depend_t, &gift_t, &taxable_t, &tax_t, &net_t) == 11) {
      printf(" %03d%20s%11.0lf%9.0lf%10.0lf%8.0lf%10.0lf%11.0lf%11.0lf%10.0lf%10.0lf\n", code_t, buffer, inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t);
    }
  }
}

Компиляция и выполнение:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra f.c
pi@raspberrypi:/tmp $ cat f
Code                Name     Income    Allow      Pens     Ins    Depend    Charity    Taxable       Tax       Net
------------------------------------------------------------------------------------------------------------------------
008                John     100000     4000      5000    1000      3200       1000      85800     20280     79720
001                 Doe      50000     4000         0     500      1600          0      43900      7725     42275
pi@raspberrypi:/tmp $ ./a.out < f
 008                John     100000     4000      5000    1000      3200       1000      85800     20280     79720
 001                 Doe      50000     4000         0     500      1600          0      43900      7725     42275
pi@raspberrypi:/tmp $ 

Обратите внимание, что нет защиты от переполнения при чтениистрока в scanf просто с %s, если лучше использовать %63s, потому что я измерил буфер 64


Небольшое изменение для поиска кода, все еще используя ваш scanf , давая имя файла и ожидаемый код в аргументе:

#include <stdio.h>

int bypassLine(FILE * fp)
{
  int c;

  for (;;) {
    c = fgetc(fp);

    if (c == EOF)
      return 0;
    if (c == '\n')
      return 1;
  }
}

int main(int argc, char ** argv)
{
  if (argc != 3)
    printf("usage : %s <file> <code>\n", *argv);
  else {
    FILE * fp;
    int code_t, expected;
    char buffer[64];
    double inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t;

    if ((fp = fopen(argv[1], "r")) == NULL) {
      fprintf(stderr, "cannot open '%f'\n", argv[1]);
      return -1;
    }

    if (!bypassLine(fp) || !bypassLine(fp)) {
      fprintf(stderr, "too short file '%s'\n", argv[1]);
      fclose(fp);
      return -1;
    }

    if (sscanf(argv[2], "%d%c", &expected, buffer) != 1) {
      fprintf(stderr, "invalid code '%s'\n", argv[2]);
    }
    else {
      while (fscanf(fp, " %3d%63s%lf%lf%lf%lf%lf%lf%lf%lf%lf", &code_t, buffer, &inc_t, &personal, &pension_t, &health_t, &depend_t, &gift_t, &taxable_t, &tax_t, &net_t) == 11) {
        if (code_t == expected) {
          printf(" %03d%20s%11.0lf%9.0lf%10.0lf%8.0lf%10.0lf%11.0lf%11.0lf%10.0lf%10.0lf\n", code_t, buffer, inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t);
          fclose(fp);
          return 0;
        }
      }
      fprintf(stderr, "code %d not found in '%s'\n", expected, argv[1]);
    }
    fclose(fp);
    return -1;
  }
}

Компиляция и выполнение:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra f.c
pi@raspberrypi:/tmp $ ./a.out ./f 2
code 2 not found in './f'
pi@raspberrypi:/tmp $ ./a.out ./f 8
 008                John     100000     4000      5000    1000      3200       1000      85800     20280     79720
pi@raspberrypi:/tmp $ 

Другой способ с использованием fseek для прямого перехода от кода к коду в файле:

#include <stdio.h>

int bypassLine(FILE * fp)
{
  int c;

  for (;;) {
    c = fgetc(fp);

    if (c == EOF)
      return 0;
    if (c == '\n')
      return 1;
  }
}

int main(int argc, char ** argv)
{
  if (argc != 3)
    printf("usage : %s <file> <code>\n", *argv);
  else {
    FILE * fp;
    int code_t, expected;
    char buffer[64];
    double inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t;

    if ((fp = fopen(argv[1], "r")) == NULL) {
      fprintf(stderr, "cannot open '%f'\n", argv[1]);
      return -1;
    }

    if (!bypassLine(fp) || !bypassLine(fp)) {
      fprintf(stderr, "too short file '%s'\n", argv[1]);
      fclose(fp);
      return -1;
    }

    if (sscanf(argv[2], "%d%c", &expected, buffer) != 1) {
      fprintf(stderr, "invalid code '%s'\n", argv[2]);
    }
    else {
      long offset = ftell(fp);

      while (fscanf(fp, " %03d", &code_t) == 1) {
        if (code_t == expected) {
          /* extract the other fields */
          if (fscanf(fp, "%63s%lf%lf%lf%lf%lf%lf%lf%lf%lf", buffer, &inc_t, &personal, &pension_t, &health_t, &depend_t, &gift_t, &taxable_t, &tax_t, &net_t) == 10) {
            printf(" %03d%20s%11.0lf%9.0lf%10.0lf%8.0lf%10.0lf%11.0lf%11.0lf%10.0lf%10.0lf\n", code_t, buffer, inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t);
            fclose(fp);
            return 0;
          }
          else {
            fprintf(stderr, "code %d found but cannot read next fields\n", code_t);
            fclose(fp);
            return -1;
          }
        }
        /* the lines are supposed having all the times 114 characters newline included */
        offset += 114;
        if (fseek(fp, offset, SEEK_SET) == -1) {
          fprintf(stderr, "error when going at offset %d of '%s'\n", offset, argv[1]);
          fclose(fp);
          return -1;
        }
      }
      fprintf(stderr, "code %d not found in '%s'\n", expected, argv[1]);
    }
    fclose(fp);
    return -1;
  }
}

Компиляция и выполнение:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra f.c
pi@raspberrypi:/tmp $ cat f
Code                Name     Income    Allow      Pens     Ins    Depend    Charity    Taxable       Tax       Net
------------------------------------------------------------------------------------------------------------------------
008                John     100000     4000      5000    1000      3200       1000      85800     20280     79720
001                 Doe      50000     4000         0     500      1600          0      43900      7725     42275
pi@raspberrypi:/tmp $ ./a.out ./f 8
 008                John     100000     4000      5000    1000      3200       1000      85800     20280     79720
pi@raspberrypi:/tmp $ ./a.out ./f 1
 001                 Doe      50000     4000         0     500      1600          0      43900      7725     42275
pi@raspberrypi:/tmp $ ./a.out ./f 11
code 11 not found in './f'
0 голосов
/ 19 марта 2019

Я хочу напечатать запись, если введенный код совпадает с кодом в файле.

Если ваша цель - просто напечатать записи (также известные как строки), где «Код» соответствует некоторому значению, заданному пользователем, ваш подход кажется слишком сложным, так как нет необходимости сканировать все поля.

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

Что-то вроде:

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


int main(int argc, char* argv[]){
  if (argc != 2)
  {
    printf("Wrong usage...\n");
    return 1;
  }
  int code_to_print = atoi(argv[1]);
  int code_read;

  FILE* fp = fopen("db.txt", "r");
  if (!fp)
  {
    printf("File error...\n");
    return 1;
  }
  char buf[1024];

  while (fgets(buf, sizeof buf, fp))
  {
    if (sscanf(buf, "%d", &code_read) == 1 && code_read == code_to_print)
    {
      printf("%s", buf);
    }
  }
  fclose(fp);
}

Используйте программу как:

./prog 8

.. как читать, если код имеет начальный 0 как этот?

Если лидирующие нули важны, вы не можете сканировать, используя %d, так как это «удалит» нули. Вместо этого вам нужно отсканировать код как слово. Как:

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


int main(int argc, char* argv[]){
  if (argc != 2)
  {
    printf("Wrong usage...\n");
    return 1;
  }

  char code_read[4] = {0};

  FILE* fp = fopen("db.txt", "r");
  char buf[1024];

  while (fgets(buf, sizeof buf, fp))
  {
    if (sscanf(buf, "%3s", code_read) == 1 && strcmp(code_read, argv[1]) == 0)
    {
      printf("%s", buf);
    }
  }
  fclose(fp);
}

Используйте программу как:

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