c ++中字符串的格式化输入

时间:2011-11-21 14:17:59

标签: c++ scanf formatted

我正在制作一个统计数据收集器,它可以读取音乐播放器的日志,并让用户显示最常被播放的十个等。作为一个菜鸟项目。

日志中的一行看起来像是:“20:42:03开始E:\ ROTATION \ A \HåkanLidbo - Dammlunga.mp3”

我已经使用ifstream和getline将它放在一个字符串中。

然后使用

创建字符串的字符数组
const char *charveqtur = newline.c_str();

然后我试着用sscanf排序:

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

问题是文件名是在第一个空格处剪切的。我也尝试过使用istringstream,但到目前为止还没有突破。

这是最方便的方法吗?感谢。

2 个答案:

答案 0 :(得分:2)

您可以使用某些输入流来读取第一个整数和冒号,并且因为文件名是最后一个实体,您可以使用std::getline。但是,即使您的文件名不是最后一部分,请注意std::getline是一个非常通用的函数,可以接受任何分隔符。

更高级的方法是为文件名定义自己的类型并在其上重载operator>>(std::istream &, T const &)

以下是使用std::getlinestringstream进行基本诊断和重新格式化的完整示例:

#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更方便。

答案 1 :(得分:0)

你可以做一些像

这样的事情
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 */
}