如何从文件中读取包含子列表的列表?

时间:2012-03-13 23:49:41

标签: c++ io

结构非常简单:

  1. 要点
    1. 列出项目 - 5
    2. 列表项目 - 6
    3. ...
  2. 要点
    1. 列出项目 - 2
    2. 列出项目 - 3
    3. ...
  3. 为了便于阅读,我添加了一些分隔符,这是实际文件:

    >Point one
    item 1      | 150
    item 2      | 20
    >Point two
    item 1      | 150
    item 2      | 10
    

    我写了一个应该读它的C ++函数。但是我在自己的逻辑中纠缠不清并犯了一个错误。可以找到它吗?

      ifstream fileR("file.txt"); 
    
      int i = 0;
      getline(fileR, sTemp);
      do {
        if(!sTemp.empty() && sTemp[0]==DELIM){
            R[0][i] = sTemp.substr(1);
            i++;
        }else{
            j = 0;
            do {
                if(!sTemp.empty() && sTemp[0] != DELIM){
                    string::const_iterator pos = find(sTemp.begin(), sTemp.end(), '|');
                    string name(sTemp.begin(), pos);
                    string a_raw(pos + 1, sTemp.end());
                    a_raw = trim(a_raw);
                    double amount(atof(a_raw.c_str()));
                    R[j+1][i].set(trim(name), amount);
                    j++;
                }else{
                    break;
                }
            }while(getline(fileR, sTemp));
        }
      }while(getline(fileR, sTemp));
    

    读取值的位置并不重要因为我试图简化这个函数,因为它实际上是一些带有动态数组的容器。我测试了它们,它们确实工作正常。所以阅读存在问题。它接缝读取第一个值很好,但之后它会造成某种混乱 如果你认为我的尝试是彻底的灾难,我会欢迎提示如何使一个真正有效的功能。

    编辑:
    我睡了个好觉,我已经修好了。这是一个wokrking版本:

      bool read =  true;
      for(int i = 0; i<n; i++) {
        if(read){getline(fileR, sTemp);}else{ read = true; }
        if(!sTemp.empty() && sTemp[0]==DELIM){
            R[i].setName(sTemp.substr(1));
            i--;
        }else{
            R[i].toFirstSubpoint();
            do {
                if(!sTemp.empty() && sTemp[0] != DELIM){
                    string::const_iterator pos = find(sTemp.begin(), sTemp.end(), '|');
                    string name(sTemp.begin(), pos);
                    string a_raw(pos + 1, sTemp.end());
                    a_raw = trim(a_raw);
                    double amount(atof(a_raw.c_str()));
                    R[i].setSubpoint(trim(name), amount);
                    R[i].toNextSubpoint();
                }else{
                    read = false;
                    break;
                }
            }while(getline(fileR, sTemp));
        }
    

    我最重要的错误是我忘记了如果在检查条件之后循环进入下一个索引并且不执行它的其他(其他)条件。

    下面的答案实际上更好的方法是更简单,更容易理解,但这次我不能使用向量,我猜我的脚本应该更快一点,因为它不使用它们。无论如何,下次我会遇到类似的情况,我将使用下面的解决方案。

1 个答案:

答案 0 :(得分:2)

你应该考虑使用像boost :: spirit这样的解析库,但是如果文件格式是可选的,那么你可以做很多事情来使它更容易解析而不用这些措施,

考虑以下日期布局

MainPoint1 iname1 ivalue1 iname2 ivalue2 iname3 ivalue3
MainPoint2 iname1 ivalue1 iname2 ivalue2

可以轻松加载以下内容。

struct item{
    std::string name;
    double value;
};

std::ostream& operator<<(std::ostream& os, const item& i)
{
    return os << i.name << " " << i.value;
} 

std::istream& operator>>(std::istream& is, const item& i)
{
    return is >> i.name >> i.value;
} 

struct point{
    std::string value;
    std::vector<item> items;
};


std::istream& operator>>(std::istream& is, point& p)
{
     std::string line;
     std::getline(is, line);
     std::stringstream ss(line);
     ss >> p.value;
     p.assign(
         std::istream_iterator<item>(ss),
         std::istream_iterator<item>());
     return is;
}


std::ostream& operator<<(std::istream& os, const point& p)
{
     os << p.value << "   ";
     std::copy(p.item.begin(), p.items.end(),
         std::ostream_iterator<item>(os, " "),
     return os;
}

int main()
{
    /*
    ** Deserailise
    */
    std::ifstream in_file("infile.dat");
    std::vector<point> points(
         std::istream_iterator<point>(in_file),
         std::istream_iterator<point>());


    /*
    ** Serailise
    */
    std::ofstream out_file("outfile.dat");
    std::copy(points.begin(), points.end()
         std::ostream_iterator<points>(out_file, "\n"));
}

这是未经测试和未编译的,但从概念上讲它应该可以工作。

编辑:代码已更改为符合名称和值的项目。