如何在 C++ 中将空格和换行符分隔的整数读入二维数组?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9570991/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:00:22  来源:igfitidea点击:

How to read space and newline separated integers into a 2D array in C++?

c++

提问by Sam Elliott

I have a .txt file of numbers (in this case all less than 100) separated by spaces, in rows separated by new lines. Something like this:

我有一个由空格分隔的数字(在本例中全部小于 100)的 .txt 文件,行中由新行分隔。像这样的东西:

 41 53 07 91 44
 52 17 13 03 21

I would like to read these numbers into a 2d array, exactly as they appear, so that spaces separate columns of the array, and new lines separate rows.

我想将这些数字读入一个 2d 数组,与它们显示的完全一样,以便空格分隔数组的列,新行分隔行。

I can get it to read the lines in as strings, but then I'm having trouble separating out individual numbers, and getting it to treat them as integers.

我可以让它将行作为字符串读取,但是我在分离单个数字并将它们视为整数时遇到了麻烦。

回答by Martin York

Try this:

尝试这个:

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

int main()
{
    // The result of the read is placed in here
    // In C++, we use a vector like an array but vectors can dynamically grow
    // as required when we get more data.
    std::vector<std::vector<int> >     data;

    // Replace 'Plop' with your file name.
    std::ifstream          file("Plop");

    std::string   line;
    // Read one line at a time into the variable line:
    while(std::getline(file, line))
    {
        std::vector<int>   lineData;
        std::stringstream  lineStream(line);

        int value;
        // Read an integer at a time from the line
        while(lineStream >> value)
        {
            // Add the integers from a line to a 1D array (vector)
            lineData.push_back(value);
        }
        // When all the integers have been read, add the 1D array
        // into a 2D array (as one line in the 2D array)
        data.push_back(lineData);
    }
}

回答by Ben Voigt

Ok, the "exactly as they appear" requirement means that you need a ragged array, in case different number of columns appear in different rows. I would use std::vector< std::vector<long> >. Each contained vector corresponds to one row.

好的,“完全按照它们出现”的要求意味着您需要一个参差不齐的数组,以防不同行中出现不同数量的列。我会使用std::vector< std::vector<long> >. 每个包含的向量对应一行。

So, each time you read a row of text, create a new empty vector.

因此,每次阅读一行文本时,请创建一个新的空向量。

Call strtolrepeatedly on the row you read, using push_backto collect them into the vector. When the output pointer is the same as the input pointer (this indicates failure, probably because you reached the end of the line), push_backthe whole vector and start the next row.

strtol在您读取的行上重复调用,push_back用于将它们收集到向量中。当输出指针与输入指针相同时(这表示失败,可能是因为你到达了行尾),push_back整个向量并开始下一行。

Something like this:

像这样的东西:

std::vector< std::vector<long> > all_data;

std::string text_row;

while(getline(fin, text_row)) {
    all_data.push_back();
    std::vector<long>& this_row = *all_data.rend();

    const char* p1 = text_row.c_str();
    const char* p2;
    while (1) {
         long num = strtol(p2 = p1, &p1, 0);
         if (p1 == p2) break;
         this_row.push_back(num);
    }

    /* to ignore blank lines, add this code
    if (this_row.empty()) all_data.pop_back();
     */
}

回答by mantler

The following code shows how to solve your problem. It also shows how you can use RAII when opening a file. This is good practice when acquiring resources. By acquiring the resource in the constructor and releasing it in the destructor a resource leak can be prevented if an exeption is thrown. This is considered good practice in the C++ world.

以下代码显示了如何解决您的问题。它还展示了如何在打开文件时使用 RAII。这是获取资源时的良好做法。通过在构造函数中获取资源并在析构函数中释放它,如果抛出异常,可以防止资源泄漏。这在 C++ 世界中被认为是很好的做法。

#include <fstream>
#include <vector>

struct FileHandle
{
  std::ifstream file_;
  FileHandle(std::string file_name)
  {
    file_.open(file_name);
  }
  ~FileHandle()
  {
    file_.close();
  }
};

bool next_char_is_end_of_line(std::ifstream &file)
{
  bool found = false;
  char c;
  file.get(c);
  if(c == '\n')
    found = true;
  file.unget();
  return found;
}

int main()
{
  FileHandle fh("c:\your_file.txt");
  std::vector<std::vector<int> > v;
  std::vector<int> current_line;
  int x;
  while(fh.file_ >> x)
  {
    current_line.push_back(x);
    if(next_char_is_end_of_line(fh.file_))
    {
      v.push_back(current_line);
      current_line.clear();
    }
  }
  //Then just access each std::vector<std::vector<int>> 
  //v[0].size(); ...
  return 0;
}

This code gives you a "jagged" vector by putting all numbers on each row into a separate vector. This vector is then added to main vector. So each line in the "vector" can have different lengths. I think you get the idea...

这段代码通过将每行上的所有数字放入一个单独的向量中,为您提供了一个“锯齿状”向量。然后将此向量添加到主向量。所以“向量”中的每一行都可以有不同的长度。我想你应该已经明白了...

Good luck!

祝你好运!

回答by Emilio Garavaglia

There are actually two problems, here:

其实这里有两个问题:

  1. how to recognize the input and ...
  2. how to represent it in memory.
  1. 如何识别输入和...
  2. 如何在内存中表示它。

You spoke about "2d Array": is this a requirement or just an hypothesis? is the 2x5 size a requirement or just a sample?

你谈到了“二维数组”:这是一个要求还是一个假设?2x5 尺寸是要求还是样品?

You spoke about a file layout. It that mandatory, or not? Must you admit (and check) eventually misleading like more numbers, or misalignment? What do you have to do in case the row have 6 numbers the first and 4 the second?

您谈到了文件布局。它是强制性的,还是不是?您是否必须承认(并检查)最终会产生误导,例如更多的数字或错位?如果第一行有 6 个数字,第二个有 4 个数字,你该怎么办?

A very simple solution can be use a 2x5 array and fill it up with a guarded loop:

一个非常简单的解决方案是使用 2x5 数组并用一个受保护的循环填充它:

#include <iostream>
#include <fstream>
#include <iomanip>
#include <stdexcept>

const int ROWS=2;
const int COLS=5;

int main(int argc, char** argv)
{
    int m[ROWS][COLS];
    try
    {
        std::ifstream s(argv[1]);
        if(!s) throw std::runtime_error("cannot open file");
        for(int r=0; r<ROWS; ++r)
            for(int c=0; c<COLS; ++c)
               if(!(s >>m[r][c])
                   throw std::runtime_error("insufficient or bad input");
    }
    catch(const std::exception& e)
    {
        std::cout << "Reading error: " << e.what() << std::endl;
        return -1;
    }

    std::cout << "read matrix is \n";
    for(int r=0; r<ROWS; ++r)
    {
        for(int c=0; c<COLS; ++c)
            std::cout << std::setw(8) << m[r][c];
        std::cout << '\n';
    }
    std::cout << std::endl;
    return 0;
}

This will read 10 numbers separated by "blanks", no matter how distributed and aligned. (it is assumend the the 2x5 is a consrain.)

这将读取由“空格”分隔的 10 个数字,无论分布和对齐如何。(假设 2x5 是一个限制。)

On the other end, you may have to detect yourself how wide the matrix is: the file can have any number of lines, each whatever number of elements long.

另一方面,您可能必须检测自己矩阵的宽度:文件可以有任意数量的行,每行都可以包含任意数量的元素。

In this case you need a "flexible structure", and you need to identify lines and elements in the lines.

在这种情况下,您需要一个“灵活的结构”,并且您需要识别线条和线条中的元素。

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <iomanip>
#include <stdexcept>
#include <utility>

int main(int argc, char** argv)
{
    std::vector<std::vector<int> > m;
    try
    {
        std::ifstream fs(argv[1]);
        if(!fs) throw std::runtime_error("cannot open input file");
        while(fs)
        {
            std::string line;
            std::getline(fs,line);
            std::vector<int> row;
            std::stringstream ss(line);
            int x;
            while(ss >> x)
               row.push_back(x); 
            if(!row.empty())
                m.emplace_back(std::move(row));
        }
    }
    catch(const std::exception& e)
    {
        std::cout << "Reading error: " << e.what() << std::endl;
        return -1;
    }

    std::cout << "read lines: \n";
    for(auto i=m.begin(); i!=m.end(); ++i)
    {
        for(auto j=i->begin(); j!=i->end(); ++j)
            std::cout << std::setw(8) << *j;
        std::cout << '\n';
    }
    std::cout << std::endl;

    return 0;
}

回答by Beta