我需要解析包含以下内容的文本文件:
1|Song Title|Release date||"ignore me"|0|0|0|1|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0
这是歌曲编号,然后是发行日期,接下来是我需要忽略的网站,然后是一系列0和1,它们可以代表流派的载体。
我需要一种方法来分离这些数据,并忽略那个说网站的方式,同时创建一个Song对象的新实例,它具有:(int songNumber,string songTitle,vector * genres,string releaseDate )
谢谢!
答案 0 :(得分:16)
C++ String Toolkit Library (StrTk)针对您的问题提供了以下解决方案:
#include <string>
#include <deque>
#include "strtk.hpp"
struct song_type
{
unsinged int id;
std::string release_date;
std::string url;
char genre[8];
};
strtk_parse_begin(song_type)
strtk_parse_type(id)
strtk_parse_type(release_date)
strtk_parse_type(url)
strtk_parse_type(genre[0])
strtk_parse_type(genre[1])
strtk_parse_type(genre[2])
strtk_parse_type(genre[3])
strtk_parse_type(genre[4])
strtk_parse_type(genre[5])
strtk_parse_type(genre[6])
strtk_parse_type(genre[7])
strtk_parse_end()
int main()
{
std::deque<song_type> song_list;
strtk::for_each_line("songs.txt",
[&song_list](const std::string& line)
{
song_type s;
if (strtk::parse(line,"|",s))
song_list.push_back(s);
});
return 0;
}
可以找到更多示例Here
答案 1 :(得分:4)
Song
,用于保存您需要的表单中的数据,如上所述Song::operator>>(const istream&);
来填充类string::getline
stringstream
,然后使用operator>>
填写Song
实例中的字段。用'|'标记字符串流是很简单的字符作为分隔符,这将是工作的主要部分。
int main()
{
std::string token;
std::string line("1|Song Title|Release date||\"ignore me\"|0|0|0|1|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0");
std::istringstream iss(line);
while ( getline(iss, token, '|') )
{
std::cout << token << std::endl;
}
return 0;
}
代码从here解除。
答案 2 :(得分:3)
您通常会通过为对象类型重载operator>>
来执行此操作:
struct song_data {
std::string number;
std::string title;
std::string release_date;
// ...
};
std::istream &operator>>(std::istream &is, song_data &s_d) {
std::getline(is, s_d.number, '|');
std::getline(is, s_d.title, '|');
std::getline(is, s_d.release_date, '|');
std::string ignore;
std::getline(is, ignore, '|');
// ...
return is;
}
根据是否有更多字段可能要忽略(尤其是尾随字段),有时可以更方便地将整行读入字符串,然后将其放入istringstream,并从那里解析各个字段。特别是,这可以避免额外的工作,阅读更多您不关心的字段,而只是在解析出您关心的字段时转到下一行。
编辑:我可能会通过添加std::vector<bool> genres;
并将0和1读入该向量来处理这些类型。然后,我会添加一个枚举,指定向量中特定位置表示的类型,因此(例如)测试某首歌是否被归类为“国家/地区”将类似于:
enum { jazz, country, hiphop, classic_rock, progressive_rock, metal /*, ... */};
if (songs[i].genres[country])
if (songs[i].genres[hiphop])
process_hiphop(songs[i]);
当然,确切的类型及其顺序是我不知道的,所以我只是编写了一些可能性 - 你(显然)必须使用为文件格式定义的类型(和顺序)
就处理数百首歌曲而言,通常的方式是(如上所述)创建类似:std::vector<song_data> songs;
的内容。使用如上所述的流提取,您可以将数据从文件复制到向量:
std::copy(std::istream_iterator<song_data>(infile),
std::istream_iterator<song_data>(),
std::back_inserter(songs));
如果您可能主要通过名称查找歌曲(例如),您可能更愿意使用std::map<std::string, song_data> songs
。这样可以很容易地执行以下操作:
songs["new song"].release_date = Today;