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

Представете си, че имам csv с и всяка стойност е цяло число. така че първата стойност е ЦЯЛО ЧИСЛО 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. вероятно бих могъл да направя едно от тези int огромни, което ще изисква инициализация на огромен масив. - 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() не са много добри в откриването на този вид грешка. Не е невъзможно (вижте отговора на Джери Кофин, който работи, но е IMO труден за генерализиране), но IMO не е толкова стабилен. По-добрият вариант е да използвате 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