首页 > 解决方案 > 如何从文本文件中读取数据并将其存储到C++中的数组中

问题描述

我正在尝试从文本文件中读取数据并将其存储到数组中。我需要它来解决 FEM 问题。假设我的文本文件如下:

node: 1,2,3,4,5,6,7,8,9,10
x: 4,4,3.75,3.76773151,3,3.59192947,4,3.5,3.55115372,3.375, 3.71330586 
y: 3,275,3,2.65921885,2.79192947,2.5,3,2.55115372,2.78349365,2.36222989 
z: 0,0,0,0,0,0,0,0,0,0                      

我想将此数据从文本文件存储到 10*4 矩阵 ( myarray[10][4]) 中。我还需要将此数组的每一列存储到一个向量中。假设我的向量是:

double x[10];
double y[10];
double z[10];

for (int i = 0; i < 10; i++)
{
    x[i] = myarray[i][1];
    y[i] = myarray[i][2];
    z[i] = myarray[i][3];
}

我写了这样的代码:

int main()
{
    string line;
    string coordinate[10][4];
    ifstream mesh("mesh.txt");

    for (int i = 0; i < 10; ++i)
    {
        for (int j = 0; j < 4; ++j)
        {
            if (getline(mesh, line, ';'))
            {
                coordinate[i][j] = line;
                cout << coordinate[i][j] << endl;
                cout << "mesh : " << line[0] << endl;
            }
        }
    }
    mesh.close();
}

现在我的问题是,当我想将每一列坐标放入一个向量时,我得到了这个错误:

不存在从字符串到双精度的合适转换函数

我不明白这个错误,需要帮助来修复它。

标签: c++arraysstringdouble

解决方案


一种迭代方式可能像这样,在定制的迭代器类中使用拆分器。它似乎很复杂,但我认为它很容易维护。请注意,迭代器类是这个好答案的修改版本。

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

template <typename T>
class istream_line_iterator : public std::iterator<std::input_iterator_tag, T> {
  std::istream* stream;

 public:
  // Creating from a stream or the end iterator.
  istream_line_iterator(std::istream& s) : stream(&s) { dropLeadingSpace(); }
  istream_line_iterator() : stream(nullptr) {}

  // Copy
  istream_line_iterator(istream_line_iterator const& copy)
      : stream(copy.stream) {}
  istream_line_iterator& operator=(istream_line_iterator const& copy) {
    stream = copy.stream;
    return *this;
  }

  // The only valid comparison is against the end() iterator.
  // All other iterator comparisons return false.
  bool operator==(istream_line_iterator const& rhs) const {
    return stream == nullptr && rhs.stream == nullptr;
  }
  bool operator!=(istream_line_iterator const& rhs) const {
    return !(*this == rhs);
  }

  // Geting the value modifies the stream and returns the value.
  // Note: Reading from the end() iterator is undefined behavior.
  T operator*() const {
    T value;
    (*stream) >> value;
    return value;
  }
  T* operator->() const;  // Not sure I want to implement this.

  // Input streams are funny.
  // Does not matter if you do a pre or post increment. The underlying stream
  // has changed. So the effect is the same.
  istream_line_iterator& operator++() {
    dropLeadingSpace();
    return *this;
  }
  istream_line_iterator& operator++(int) {
    dropLeadingSpace();
    return *this;
  }

 private:
  void dropLeadingSpace() {
    // Only called from constructor and ++ operator.
    // Note calling this on end iterator is undefined behavior.

    char c;
    while ((*stream) >> std::noskipws >> c) {
      if (c == '\n') {
        // End of line. So mark the iterator as reaching end.
        stream = nullptr;
        return;
      }
      if (!std::isspace(c) && c != ',') {
        // Found a non space character so put it back
        stream->putback(c);
        return;
      }
    }
    // End of stream. Mark the iterator as reaching the end.
    stream = nullptr;
  }
};

int main() {
  std::ifstream ifs("1.in");
  std::string line;
  std::vector<std::vector<double>> vec;
  while (std::getline(ifs, line)) {
    std::istringstream iss(line);
    std::string pre;
    iss >> pre;

    std::vector<double> line_vec;
    auto beg = istream_line_iterator<double>(iss);
    auto end = istream_line_iterator<double>();

    std::copy(beg, end, std::back_inserter(line_vec));
    vec.push_back(std::move(line_vec));
  }
  for (const auto& inner : vec) {
    for (auto d : inner) {
      std::cout << d << ' ';
    }
    std::cout << std::endl;
  }

  return 0;
}


推荐阅读