解析文本文件,创建新对象c ++的实例

时间:2010-11-26 20:39:51

标签: c++

我需要解析包含以下内容的文本文件:

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 )

谢谢!

3 个答案:

答案 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;