Форматный ввод на C++

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Ответить
Павел Легков
Сообщения: 6
Зарегистрирован: 06 апр 2017, 10:41

06 апр 2017, 10:43

Джентльмены, всем доброго времени суток!
У меня вопрос по форматному вводу C++.
Задача следующая – нужно читать исходные данные (числа) из текстового файла древнего формата.
Каждое число записано в поле длиной восемь символов, т.е. строка файла представляет собой нечто следующее:
123 34.78 54.123 и т.п.
Проблема в том, что число может занимать все восемь символов, и тогда между соседними числами не будет пробелов. Для Fortrana здесь проблем нет, такой формат можно читать стандартными фортрановскими средствами без применения специальных ухищрений. А для C++ я не придумал ничего лучшего, чем:
чтение строки из файла целиком,
принудительная вставка пробелов между полями в прочитанную строку,
создание входного строкового потока на основе полученной строки,
и только после этого чтение чисел из указанного входного строкового потока .
Не подскажете, может быть есть способ попроще, не прибегаю к ухищрениям?
С уважением, Павел.
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

06 апр 2017, 10:58

Ну можно копировать в цикле по 8 символов в отдельный буфер, и потом преобразовывать из него в число. Наверное проще будет выглядеть код. Но в любом случае так, чтобы прочитать все числа одним махом из подобной хитрой строки, не меняя её, никак не получится.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Павел Легков
Сообщения: 6
Зарегистрирован: 06 апр 2017, 10:41

06 апр 2017, 18:28

Большое спасибо!
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

06 апр 2017, 18:57

Можно даже в том же самом буфере всё делать.

Код: Выделить всё

char buff[256];
scanf("%s", buff);

auto curr = buff;
while (*curr != '\0')
{
   auto next = curr + 8;
   auto old = *next;
   *next = '\0';

   float value = .0;
   sscanf(curr, "%f", &value);
   printf("%f ", value);

   *next = old;
   curr = next;
}
P.S. Пример кода намеренно написан в С-style, так как работа напрямую с памятью там более лаконична.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Skwoogey
Сообщения: 63
Зарегистрирован: 11 янв 2016, 02:25

07 апр 2017, 13:20

Еще можно резать строку этой функцией, а потом парсить этой.
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

07 апр 2017, 17:42

Нет, резать strtok не получится. У нас нет делиметра. Числа могут быть "слипнуты" :)
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Skwoogey
Сообщения: 63
Зарегистрирован: 11 янв 2016, 02:25

10 апр 2017, 00:41

Кстати, а fcnanf не получится?

Код: Выделить всё

fscnaf(file, "%8f", a);
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

10 апр 2017, 16:20

Да, чёрт побери, работает :)

Код: Выделить всё

char buff[256];
float value = .0;

scanf("%s", buff);
 
for (auto curr = buff; *curr != '\0'; curr += 8)
{
   sscanf(curr, "%8f", &value);
   printf("%f ", value);
}
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Skwoogey
Сообщения: 63
Зарегистрирован: 11 янв 2016, 02:25

10 апр 2017, 20:17

а с std::cout есть такой же быстрый и эффективный способ форматирования текста, как с printf? Гугл мне выдавал только, что-то неудобное, по типу setw(), setfill().
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

11 апр 2017, 12:01

Точно такого же нет. Это делается через упомянутые манипуляторы и, в общем-то, запись получается тоже достаточно лаконичной.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Ответить