Подтвердить что ты не робот

Как сканировать поплавок сразу же после буквы "e" в c?

Я пытаюсь использовать fscanf для чтения в данных, а частью ввода является поплавок, за которым следует буква 'e', например, 41.72elapsed. При написании strng для fscanf я попытался использовать "%felapsed", но это не работает, поскольку %fe является его собственным спецификатором формата. Как я прочитал бы это при использовании fscanf?

изменить: Вот код:

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

#define CHAR_MAX 1024

int main(int argc, char **argv)
{
    FILE *file_in = fopen(argv[1], "r+");
    char out_name[CHAR_MAX];
    strcpy(out_name, argv[1]);
    strcat(out_name, ".csv");
    FILE *csv_out = fopen(out_name, "w");
    int minutes;
    float seconds;
    fprintf(csv_out, "Trial #, Execution Time\n");

    for (int i = 0; fscanf(file_in, "%*fuser %*fsystem %d:%felapsed %*d%%CPU (%*davgtest+%*davgdata %*dmaxresident)k\n%*dinputs+%*doutputs (%*dmajor+%*dminor)pagefaults %*dswaps\n", &minutes, &seconds) == 2; i++) {
         fprintf(csv_out, "%d, %d:%.2f\n", i, minutes, seconds);
     };
    return 0;
}

Вот пример ввода:

283.97user 0.69system 1:13.77elapsed 385%CPU (0avgtext+0avgdata 107472maxresident)k

0inputs+4616outputs (0major+9550minor)pagefaults 0swaps

287.87user 0.35system 1:14.41elapsed 387%CPU (0avgtext+0avgdata 107328maxresident)k

0inputs+4616outputs (0major+9524minor)pagefaults 0swaps
4b9b3361

Ответ 1

Это проблема с scanf()

Форматы FP, такие как "%f", рассматривают e как введение экспоненциальности. Поскольку e не следует числом, сканирование для float останавливается. Но scanf() все готово сканируется один за e, а C не требует для scanf() возможности резервного копирования более 1 символа. Таким образом, код не удался, используя простой "%f".

Некоторые системы будут поддерживать более 1 символа, но C не требует этой возможности.

Код нуждается в новом подходе - сканирование в секундах в виде строки

char sec[20];
int cnt = fscanf(file_in, "%d:%19[0-9. ]elapsed", &minutes, sec);
if (cnt == 2) {
  seconds = atof(sec); 
  ...
}

Ответ 2

Просто нет необходимости в "elapsed" в вашем формате. scanf family функции будет считываться до тех пор, пока они могут со входа, а для числа с плавающей запятой он перестанет читать, когда он попадет символ без цифры, т.е. e в elapsed.

Таким образом, формат должен быть "%f", и что он. То есть.

float value;
fscanf(file, "%f", &value);

Если вы хотите прочитать и отбросить часть elapsed, используйте "%*s", звездочка сообщает scanf (и семье) читать и игнорировать остальные, поэтому полный вызов будет выглядеть как

float value;
fscanf(file, "%f%*s", &value);

После просмотра кода, это может быть намного проще и проще с чем-то вроде

char input[512];
for (int i = 0; fgets(input, sizeof input, file_in) != NULL; ++i) {
    if (sscanf(input, "%*f%*s %*f%*s %d:%f%*s", &minutes, &seconds) == 2) {
        fprintf(csv_out, "%d, %d:%.2f\n", i, minutes, seconds);
    }
}

Поскольку этот цикл использует fgets вместо прямого fscanf, вы будете читать все строки во входном файле, а не только первый. Кроме того, поскольку используется fgets, нам не нужна функция sscanf для фактического анализа частей строки, которая нам не нужна (что больше всего), вместо этого мы имеем только sscanf синтаксический анализ входной строки до тех пор, пока у нас есть данные, которые нам нужны.

Ответ 3

Это немного взломать и может быть слишком хрупким, но:

Поплавок, который вы хотите разбор, похоже, является временем в минуту. Второй формат с положительными целыми числами. Если производитель данных надежно заполняет небольшие цифры нулем (например, 1: 02.03), вы можете просто использовать фиксированную длину поля 5, поскольку секунды и минуты никогда не будут больше 59 и, следовательно, всегда будут иметь два символа в ширину:

sscanf("12.345678", "%5f%s, &f, buf)
будет читать 12.34 в f и 5678 в buf. (То же самое, конечно же, с "12.34lapsed". Я просто хотел, чтобы было безошибочно ясно, что потребляется только 5 символов ввода.)

Ответ 4

Сделайте эксперимент:

#include <stdio.h>

int main (void)
{
    float fp;
    scanf("%f", &fp);
    printf("%f", fp); 
}

Вход: 123e4

Выход: 1230000.000000

Как вы можете видеть, "e" считается частью числа с плавающей запятой, указанного "% f".

Для меня самым простым решением является использование scanf("%f%*s ", &f);. После отклонения "% f" "истекший" потребляется "% * s", не вызывая проблем. Когда дело доходит до "e", оно просто отбрасывается, поскольку спецификация C имеет сноску "fscanf отбрасывает не более одного входного символа на входной поток".

BTW: Вам нужно обрабатывать числа с плавающей запятой? Если нет, то как просто рассматривать их как строки? Например, scanf("%[^e]elapsed", str);?