C - как заставить fscanf() определить, является ли то, что он читает, только цифрами, а не символами

Представьте, что у меня есть csv, и каждое значение является целым числом. поэтому первое значение - INTEGER 100.

Я хочу, чтобы fscanf() прочитал эту строку и либо сказал мне, что это ТОЛЬКО целое число, либо нет. Таким образом, он пройдет 100, но потерпит неудачу 100t. То, что я пытался получить, это "%d", где запятая является разделителем моего CSV. так что вся функция

fscanf(fp, "%d,", &count)

К сожалению, это не работает на «100t», работает на «100» и работает на «t». так что он просто не различает 100 и 100t (все эти числа, конечно, после запятых


person Tony Stark    schedule 11.04.2010    source источник


Ответы (6)


Вместо этого используйте strtol.

person Marcelo Cantos    schedule 11.04.2010
comment
что, если я понятия не имею, какой длины может быть первый int? мне нужно объявить массив строк перед передачей в fscanf. предположительно, я мог бы сделать одно из этих целых чисел огромным, что потребовало бы инициализации огромного массива. - person Tony Stark; 11.04.2010
comment
@hatorade - Нет, тип int будет переполняться задолго до того, как самое большое число вы можете сохранить в char[80]. - person Chris Lutz; 11.04.2010

Вы не знаете.

Проблема в том, что fscanf() не очень полезен. Лучший способ справиться с этим - прочитать всю строку (или значительную часть строки), а затем проанализировать строку. Вот пример:

int value;
char *extra;
char buffer[100];

// read in some data from the buffer
fgets(buffer, sizeof buffer, stdin);

// parse out a digit, if we can
i = strtol(buffer, &extra, 0);

На этом этапе вы можете проверить extra, чтобы увидеть, есть ли какие-либо дополнительные символы, что означает, что строка не была просто числом, или если extra указывает на начало buffer, это означает, что не было числа для анализа.

person Chris Lutz    schedule 11.04.2010

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

Полезные моменты: прежде всего, используйте возвращаемое значение из fscanf — оно говорит вам, сколько элементов было преобразовано. Во-вторых, преобразование «набора сканов» может быть чрезвычайно полезным. Рассмотрим следующее (я использовал sscanf, чтобы не требовать внешнего файла, но fscanf отличается только источником, из которого он считывается):

#include <stdio.h>

int main() { 
    int i;
    char *test[] = {
        "100,",    // should succeed.
        "100t,",   // should fail.
        "t"        // should also fail.
    };

    for (i=0; i<3; i++) {
        int count;
        char ch[2];
        if (2 == sscanf(test[i], "%d%[,]", &count, &ch))
            fprintf(stderr, "Conversion of \"%s\" succeeded.\n", test[i]);
        else
            fprintf(stderr, "Conversion of \"%s\" failed.\n", test[i]);
    }
    return 0;
}
person Jerry Coffin    schedule 11.04.2010

Как насчет

fscanf(fp, "%d%c", &count, &aChar)

если aChar != ',' && != '\n', то у вас есть не только целое число

person mcabral    schedule 11.04.2010

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

использование atoi на одном токене, таком как «100t», даст 0, тогда как «100» даст 100

person AndersK    schedule 11.04.2010

Семейство функций scanf() не очень хорошо справляется с обнаружением такого рода ошибок. Это не невозможно (см. ответ Джерри Коффина, который работает, но ИМО трудно обобщить), но ИМО не так уж надежен. Лучший вариант — использовать fgets() для чтения ввода в виде текста, токенизировать с помощью strtok() или аналогичного, а затем использовать strtol() или strtod() для преобразования токенов в числовые значения:

char buffer[LINE_SIZE];
while (fgets(buffer, sizeof buffer, inFile))
{
  char *token;
  char *newline = strchr(buffer, '\n');
  if (newline) 
    *newline = 0;
  token = strtok(buffer, ",");
  while (token)
  {
    char *chk;
    int value = (int) strtol(token, &chk, 10);
    if (!isspace(*chk) && *chk != 0)
    {
      printf("%s is not a valid integer\n", token);
    }
    else
    {
      printf("successfully read integer value %d\n", val);
    }
    token = strtok(NULL, ",");
  }
}

if (feof(inFile))
{
  printf("Hit end-of-file\n");
}
else
{
  printf("Error during read\n");
}
person John Bode    schedule 11.04.2010