如何将文件中的字符转换成二维向量?

时间:2019-07-06 07:11:41

标签: c++ c++11 file-io 2d-vector

我一直在尝试从外部文件中读取字符,并将其放入类型为char的二维向量中。这些元素必须能够与某些值进行比较,以导航“ MazeSample.txt”中给定的迷宫。

虽然我无法将字符放入向量中,但我可以使用getcout函数读取和输出字符。 以下代码试图读取正确格式的向量,但最后提供了一个错误:

//MazeSample.txt
SWWOW
OOOOW
WWWOW
WEOOW

//source.cpp
vector<vector<char>> maze;
ifstream mazeFile;
char token;

mazeFile.open("MazeSample.txt");

while (!mazeFile.eof()) {
    mazeFile.get(token); //reads a single character, goes to next char after loop

    for (int row = 0; row < maze.size(); row++) {
        for (int column = 0; column < maze.at(row).size(); row++) {
            maze.push_back(token);
        }
    }

    //cout << token;
}

mazeFile.close();

对于“ MazeSample.txt”中提供的迷宫,我希望maze向量能够逐行读取每个字符,从而模仿迷宫示例的格式。

在上面的代码中,maze.push_back(token)处出现错误:     “没有重载函数“ std :: vector <_Ty,_Alloc> :: push_back ...”的实例与参数列表匹配”     “参数类型为:(字符)”     “对象类型为:std :: vector>,std :: allocator >>>”

2 个答案:

答案 0 :(得分:2)

您正在向char插入vector<vector<char>>。您应该创建一个vector<char>,在其中插入类型char的值,然后将vector<char>插入vector<vector<char>> maze;。这是程序的正确版本。可以用简单的方式编写它,但是为了您的理解,我对您的程序进行了更正。

vector<vector<char>> maze;
ifstream mazeFile;
string token;

mazeFile.open("MazeSample.txt");

while (!mazeFile.eof()) {
    std::getline(mazeFile, token); //reads an entire line

    //Copy characters in entire row to vector of char
    vector<char> vecRow;
    vecRow.assign(token.begin(), token.end());

    //Push entire row of characters in a vector
    maze.push_back(vecRow);

}

mazeFile.close();

答案 1 :(得分:1)

出现问题的原因是您尝试将char放入std向量的std :: vector中。所以您输入了错误的类型。

maze.at(row).push_back(token);可以做到,但随后不存在任何行。您还需要push_back并清空行,然后才能向其中写入数据。

那是您的语法错误。

然后,使用C ++算法可以大大缩短您的代码。参见:


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


std::istringstream testDataFile(
R"#(00000
11111
22222
33333
44444
)#");



// This is a proxy to read a complete line with the extractor operator
struct CompleteLineAsVectorOfChar {
    // Overloaded Extractor Operator
    friend std::istream& operator>>(std::istream& is, CompleteLineAsVectorOfChar& cl) {
        std::string s{}; cl.completeLine.clear();  std::getline(is, s); 
        std::copy(s.begin(), s.end(), std::back_inserter(cl.completeLine));
        return is; }

    operator std::vector<char>() const { return completeLine; }  // Type cast operator for expected value
    std::vector<char> completeLine{};
};


int main()
{
    // Read complete source file into maze, by simply defining the variable and using the range constructor
    std::vector<std::vector<char>> maze { std::istream_iterator<CompleteLineAsVectorOfChar>(testDataFile), std::istream_iterator<CompleteLineAsVectorOfChar>() };

    // Debug output:  Copy all data to std::cout
    std::for_each(maze.begin(), maze.end(), [](const std::vector<char> & l) {std::copy(l.begin(), l.end(), std::ostream_iterator<char>(std::cout, " ")); std::cout << '\n'; });

    return 0;
}

但这还没有结束。 std::vector<char>比字符串没有优势。您几乎可以拥有与std::vector<char>相同的功能。那是设计上的改进。该代码将看起来像这样:

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

std::istringstream testDataFile(
R"#(00000
11111
22222
33333
44444
)#");

int main()
{
    // Read complete source file into maze, by simply defining the variable and using the range constructor
    std::vector<std::string> maze{ std::istream_iterator<std::string>(testDataFile), std::istream_iterator<std::string>() };

    // Debug output:  Copy all data to std::cout
    std::copy(maze.begin(), maze.end(), std::ostream_iterator<std::string>(std::cout, "\n"));

    return 0;
}

这是更简单的解决方案。它将同样满足您的需求。

请注意:因为我在SO上没有文件,所以我使用istringstream读取数据。但这与使用其他任何流(例如ifstream)的原因相同。

编辑

第一个解决方案读取源并将其直接放入std::vector<std::vector<char>>

第二个解决方案将所有内容放入std::vector<std::vector<std::string>>中,这是最有效的解决方案。另外,std::string几乎是std::vector<std::vector<char>>

OP请求了第三种解决方案,我们使用第二种解决方案,然后将std::vector<std::vector<std::string>>复制到std::vector<std::vector<char>>中。

请参阅下文


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

std::istringstream testDataFile(
    R"#(00000
11111
22222
33333
44444
)#");

int main()
{
    // Read complete source file into maze, by simply defining the variable and using the range constructor
    std::vector<std::string> maze{ std::istream_iterator<std::string>(testDataFile), std::istream_iterator<std::string>() };

    // Debug output:  Copy all data to std::cout
    std::copy(maze.begin(), maze.end(), std::ostream_iterator<std::string>(std::cout, "\n"));


    // Edit: Copy into a std::vector<std::vector<char> -------------------------------------------------------
    std::cout << "\n\n\nSolution 3:\n\n";

    // Define the new variable with number of lines from the first maze
    std::vector<std::vector<char>> mazeChar(maze.size());

    // Copy the data from the original maze
    std::transform(
        maze.begin(),               // Source
        maze.end(), 
        mazeChar.begin(),           // Destination
        [](const std::string & s) {
            std::vector<char>vc;    // Copy columns
            std::copy(s.begin(), s.end(), std::back_inserter(vc)); 
            return vc; 
        }
    );

    // Debug Output
    std::for_each(
        mazeChar.begin(),
        mazeChar.end(),
        [](const std::vector<char> & vc) {
            std::copy(vc.begin(), vc.end(), std::ostream_iterator<char>(std::cout));
            std::cout << '\n';
        }
    );

    return 0;
}

希望这会有所帮助。 。