在循环中使用stringstream

时间:2018-06-20 19:23:03

标签: c++ c++11

如果这段文字过多,我的问题总结在本页底部。无论如何,我试图从包含原子及其类型列表的文件中读取行,格式如下:

   Li   O    Ti   La
 1    24     8     5

这个例子有四个元素,共有38个原子,但是我正在编写代码以容纳任意数量的元素。无论内容如何,​​元素符号始终在一行上,原子始终在另一行上。我认为执行此操作的最佳方法是使用getline将每一行插入字符串中,然后使用stringstream适当地解析这些字符串。但是事实证明,任意大小的考虑对我来说是个问题。我使用stringstream的尝试:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

int main() {
  string line;
  int num_elements;
  struct Element {
    string symbol;
    int count;
  };
  Element* atoms_ptr = NULL;  //to be allocated
  ifstream myfile("filename");
  getline(myfile, line);
  num_elements = (int)(line.size()/5);  //symbols in file have field width 5
  atoms_ptr = new Element[num_elements];
  for (int i=0; i<num_elements; ++i) {
        stringstream(line) >> (*(atoms_ptr+i)).symbol;  //does not work
      }
      getline(myfile, line);
      for (int i=0; i<num_elements; ++i) {
        stringstream(line) >> (*(atoms_ptr+i)).count;  //does not work
      }
...
return 0;
}

您可能已经意识到我的stringstream语句的问题。而不是一次读取四个元素中的每个元素,而是将第一个元素读取四次。因此,数组中每个条目的.symbol成员都初始化为Li。与原子数类似,.count成员被初始化为1。

通过这种方式重建循环,我能够编写出预期的功能:

int j = 3;
for (int i=0; i<num_elements; ++i) {
  (*(atoms_ptr+i)).symbol = line.substr(j, 2);
  j += 5;
  cout << (*(atoms_ptr + i)).symbol << '\n';
}

但是我不喜欢这种解决方案,因为它取决于确切的文件间距,不是特别可读,而且我仍然不知道如何正确使用stringstream。

从根本上讲,我认为问题是由我在循环中使用stringstream导致的。也许每次迭代都会重置字符串文件指针的位置?如果是这样,我将需要一个解决方法。我将不胜感激可以提供的任何帮助。提前致谢!

2 个答案:

答案 0 :(得分:3)

这应该可以解决问题

#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
#include <vector>

struct Element
{
    std::string symbol;
    int count;
};

int main()
{
    std::ifstream myfile("test.txt");

    std::vector<std::string> tokens(
        (std::istream_iterator<std::string>(myfile)),
        (std::istream_iterator<std::string>()));

    myfile.close();

    std::vector<Element> elements;

    const size_t numEntries = tokens.size() / 2;

    for (size_t i = 0; i < numEntries; i++)
    {
        elements.push_back({ tokens[i], std::stoi(tokens[i+ numEntries]) });
    }

    return 0;
}

一些解释:

它首先将文件内容读入字符串向量中(上半部分是元素名称,第二部分是计数) 然后在向量上运行,并将信息汇总为Element的向量(在途中将计数转换为整数)

答案 1 :(得分:1)

好的,这里有一些建议对您有帮助:

  1. 摆脱Element并使用map<string, int>
  2. 接下来使用istream_iterator进行填充

鉴于希望验证的ifstream myfile和目标输出map<string, int> atoms,您可以使用istream_iterator这样的东西:

string line;

getline(myfile, line);

istringstream myline{ line };

transform(istream_iterator<string>{ myline }, istream_iterator<string>{}, istream_iterator<int>{ myfile }, inserter(atoms, end(atoms)), [](const auto& key, const auto& value){ return make_pair(key, value); });

Live Example