【问题标题】:Storing text file into a class将文本文件存储到类中
【发布时间】:2013-12-17 00:06:33
【问题描述】:

我目前正在尝试将字符读入一个看起来像这样的类

 struct data {
    string segment; string name;
    double length; double radius; double wall_thickness;
    double young_modulus; double compliance;

};

我还有一个包含以下元素的向量:

  2A
  Aorta_Ascendens
  2
  1.47
  .164
  4
  53.4
  2B
  Aorta_Ascendens
  2
  1.44
  .161
  4
  51.0
  3A

我想将文本文件读入每个部分,目前这是我不断读取文本文件并分别添加每个部分的算法。

int place = 0;

        while (place != temp_data.size()){
            int counter = 0;
            for (counter; counter <= 7; ++counter){
                istringstream is(temp_data[place + counter]);

                if (counter == 0){ is >> a.segment; }
                if (counter == 1){ is >> a.name; }
                if (counter == 2){ is >> a.length; }
                if (counter == 3){ is >> a.radius; }
                if (counter == 4){ is >> a.wall_thickness; }
                if (counter == 5){ is >> a.young_modulus; }
                if (counter == 6){ is >> a.compliance; }

            }
            counter = counter - 1;     //since the next segment is at    temp_data[7], must subtract one to have place = 7.
            place = counter + place;

            v.push_back(a);
        }

我遇到的问题是试图找到一种方法来确保文本的正确部分进入对象的正确部分。对于前七行文本,对象应该是这样的:

segment: 2A
name: Aorta_Ascendens
length: 2
radius: 1.47
wall_thickness: .164
young modulus: 4
compliance: 53.4

这应该对整个文本文件重复相同的方式。 temp_data 是一个向量,其中包含需要添加到对象中的元素,但是我找不到一个好的方法来不断循环遍历向量并将元素放入正确的位置。

我制作的算法有一个计数器和一个占位符,计数器将循环遍历向量点,占位符将保存第一个对象的数据成员的位置,在本例中为段。在算法结束时,place 应该等于 temp_data 的大小并退出循环。但是我在编译和运行时遇到了问题,它似乎将错误的元素放入了错误的对象成员中。

有什么想法吗?

【问题讨论】:

    标签: c++ algorithm parsing vector istringstream


    【解决方案1】:

    解决此问题的一种简单、干净的方法是编写自定义流操作符:

    struct data {
        string segment; string name;
        double length; double radius; double wall_thickness;
        double young_modulus; double compliance;
    
        friend std::istream& operator>>(std::istream& is, data& d)
        {
            return is >> d.segment >> d.name >> d.length >> d.radius >> d.wall_thickness
                      >> d.young_modulus >> d.compliance;
        }
    };
    

    没有temp_dataistringstreamcounter

    要使用这个:

    data d;
    while (input_stream >> d)
        v.push_back(d);
    if (input_stream.fail())
        ...print error / exit or whatver...
    else
        ...use v...
    

    (有更多的声明方式可以使用标准算法和back_inserter 迭代器从流复制到向量,但恕我直言,简单明了是好的)

    【讨论】:

      【解决方案2】:
      • 手动方法

      您可以使用更经典的方法在文件格式中使用映射(也就是说,如果您可以访问文件的规范(内容))。

      您已经给出了文本应该是什么样子的完美示例:

      segment: 2A
      name: Aorta_Ascendens
      length: 2
      radius: 1.47
      wall_thickness: .164
      young modulus: 4
      compliance: 53.4
      

      这种格式有什么问题? 因此,它提供了更好的灵活性(安全性),因为您可以检查成员是否是您期望阅读的内容。 您可以使用分隔符分隔对象:

      segment: 2A
      name: Aorta_Ascendens
      length: 2
      radius: 1.47
      wall_thickness: .164
      young modulus: 4
      compliance: 53.4
      **@**
      segment: 2B
      name: Aorta_Ascendens
      length: 3
      radius: 1.00
      wall_thickness: .164
      young modulus: 4
      compliance: 53.4
      

      使用 ifstream.readlines() 获取 C++ 样式字符串数组,这将帮助您使用 find() 函数进行解析(如果未找到则返回 string::npos)。
      在 Parse() 函数中,它涉及遍历文件的行, 首先,使用find 查找: 字符,使用substr 获取左侧部分来检查分配值的成员(以及如何解析、整数、枚举...)和另一个substr进行一些计算(例如size - posfound)来选择正确的部分,并将其放入您选择的lexical_castboost::lexial_caststd::istringstream

      • 升压方式

      否则,您可以选择使用boost::serialization,它只允许您编写一个超级简单的函数来读取这种格式。 (参见附件)

      • 数据绑定(到 xml、jason、ini...)

      或者更复杂的数据绑定框架,例如 Code Synthesis XSD (Xerces?):
      http://www.codesynthesis.com/products/xsd/

      • Python !

      更简单的是,使用 python。你只需要做eval()

      PS:附件(带有boost::serialization)取自文档:

      class gps_position
      {
      private:
          friend class boost::serialization::access;
          // When the class Archive corresponds to an output archive, the
          // & operator is defined similar to <<.  Likewise, when the class Archive
          // is a type of input archive the & operator is defined similar to >>.
          template<class Archive>
          void serialize(Archive & ar, const unsigned int version)
          {
              ar & degrees;
              ar & minutes;
              ar & seconds;
          }
          int degrees;
          int minutes;
          float seconds;
      public:
          gps_position(){};
          gps_position(int d, int m, float s) :
              degrees(d), minutes(m), seconds(s)
          {}
      };
      

      这不是愚蠢的简单吗?它保证工作。 (只要您使用相同的序列化程序编写文件)。
      参考http://www.boost.org/doc/libs/1_55_0/libs/serialization/doc/index.html

      【讨论】:

        猜你喜欢
        • 2023-03-15
        • 2020-01-22
        • 2015-03-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多