2016-03-18 4 views
13

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

редактировать: Вот код:

#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 
+0

«*'% fe' - это собственный спецификатор формата. * " Это? Что бы это ожидало? – alk

+1

Да, это так. e указывает научную нотацию с показателем. Причина моего вопроса заключается в том, что, фактически протестировав это, использование% fe не работает по этой причине. – user2093696

+0

"* e указывает научную нотацию *" нет, это не так. Возможно, вы имеете в виду '% e', это последнее эквивалентно'% f'. Спецификаторы преобразования не являются суффиксами. Также не существует модификатора длины 'f'. – alk

ответ

4

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

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

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

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

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, анализируя входную строку, пока мы не получим нужные нам данные ,

+2

Joachim, кажется, что его реализация/компилятор/библиотека поглощает «e» как начало научной нотации. Затем чтение не выполняется, но оно не отталкивает «e». –

+0

Да, это то, что, похоже, происходит на основе того, что я вижу. – user2093696

+0

Да, символ '*', * * символ подавления присваивания * должен выполнять эту работу. :-) – alk

6

Это проблема с 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); 
    ... 
} 
+0

Это очень плохо. В любом случае, спасибо за совет, я попробую ваше решение. – user2093696

+0

@ user2093696 Примечание: C spec имеет сноску «fscanf отбрасывает не более одного входного символа на входной поток». – chux

+0

Вы также можете видеть, что это требование требуется стандартом при обсуждении «входных элементов» (7.19.6.2.9 на n1256). «Элемент ввода определяется как самая длинная последовательность входных символов, которая не превышает любую указанную ширину поля и которая является или является префиксом соответствующей последовательности ввода. Первый символ, если он есть, после ввода остается непрочитанным ». Поэтому мне кажется, что даже если реализация могла оттолкнуть больше символов, это было бы запрещено. Имеет смысл, что вам нужно детерминированное поведение, даже если оно не идеально. –

1

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

#include <stdio.h> 

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

ввода: 123e4

Выходные: 1230000.000000

As вы можете видеть, что «e» рассматривается как часть с плавающей запятой n umber указано «% f».

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

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

+0

В случае OP '' e '' '' истекшего '' потребляется ''% f '', поэтому следующий' '% * s' 'не будет использовать' 'истекший'', но '' истек «'. – chux

+0

#include int main (void) { \t float fp, fp1; \t char str [100]; \t зсапЕ ("% F% S% F", & ∥f∥p, ул, &fp1); \t Е ("% F |% s |% F", ∥f∥p, ул, FP1); } –

+0

Входной сигнал: '123ert456 789'; Выход: '123.000000 | ert456 | 789.000000' –

2

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

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

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