Форматированный ввод из строки в C ++ - PullRequest
1 голос
/ 21 ноября 2011

Я делаю сборщик статистики, который читает журнал музыкального проигрывателя и позволяет пользователю отображать десятку самых популярных и т. Д. Как проект noob.

Строка из журнала выглядит так: «20:42:03 начало E: \ ROTATION \ A \ Håkan Lidbo - Dammlunga.mp3 "

Я поместил это в строку, используя ifstream и getline.

Затем создаю массив символов изСтрока с использованием

const char *charveqtur = newline.c_str();

Затем я попытался разобраться в i с помощью sscanf:

sscanf (charveqtur, "%d:%d:%d\tstart\t%s", &this->hour, &this->minute, &this->second, &this->filename);

Проблема в том, что имя файла вырезано в первом пробеле.Я также попытался использовать istringstream вместо этого, но пока что ничего не изменилось.

Какой самый удобный способ сделать это?Спасибо.

Ответы [ 2 ]

2 голосов
/ 21 ноября 2011

Вы можете использовать некоторый входной поток для чтения первых целых чисел и двоеточий, а поскольку имя файла является последней сущностью, вы можете использовать std::getline.Тем не менее, даже если ваше имя файла не является последней частью, обратите внимание, что std::getline является довольно универсальной функцией, которая принимает любой разделитель.

Более продвинутым методом будет определение вашего собственного типа для имен файлов и перегрузки operator>>(std::istream &, T const &) на нем.

Вот полный пример использования std::getline и stringstream с базовой диагностикой и некоторым переформатированием:

#include <sstream>  // for istringstream
#include <iostream> // for cout and cerr
#include <iomanip>  // for setprecision
#include <cmath> 

bool read (std::string const &line) {
    char c = 0;
    double length;
    double rating;
    std::string title;

    std::istringstream ss;
    ss.str (line);
    ss >> length;        
    if (!ss.good())    { std::cerr << "invalid length\n"; return false; }
    if (ss.get()!=':') { std::cerr << "expected colon\n"; return false; }
    ss >> rating;
    if (!ss.good())    { std::cerr << "invalid rating\n"; return false; }
    if (ss.get()!=':') { std::cerr << "expected colon\n"; return false; }
    std::getline (ss, title);


    double sink;
    std::cout << title << " (" 
              << int(length) << ':' << 60*std::modf (length,&sink)
              << " min), your rating: " << rating << '\n';

    return true;
}

int main () {
    read ("30.25:5:Vivaldi - The four seasons.ogg");
    read ("3.5:5:Cannibal Corpse - Evisceration Plague.ogg");
    read ("meh");

    return 0;
}

Вывод:

Vivaldi - The four seasons.ogg (30:15 min), your rating: 5
Cannibal Corpse - Evisceration Plague.ogg (3:30 min), your rating: 5
invalid length

Важно : при разборе вы приближаетесь к угрозам безопасности.Всегда будьте осознанными и разумными и старайтесь по возможности использовать проверенные и проверенные библиотеки.Это также означает, что вы не используете sscanf, что не типизировано , подвержено ошибкам , а иногда трудно получить право .

Не используйте C, если вы используете C ++ и используете правильно, iostreams даже удобнее, чем printf / scanf + co.

0 голосов
/ 21 ноября 2011

Возможно, вы могли бы сделать что-то вроде

int lastpos = 0;
if sscanf (charveqtur, "%d:%d:%d\tstart\t%n", &this->hour, 
           &this->minute, &this->second,
           &lastpos) > 3 && lastpos >0) {
    std::string filename = newline.substr(lastpos);
    /* do something with filename */
}
...