繁体   English   中英

读取包含二维矩阵和相关数据的文本文件

[英]Read text file containing 2D matrix and associated data

我有一个结构如下的文本文件:

6
0,2,0,0,5,0
3,0,4,0,0,0
0,0,0,6,1,0
0,0,0,0,2,0
0,0,0,0,2,4
1,0,0,0,0,0
0,5

第一个数字表示顶点数,二维矩阵是邻接矩阵。 最后一行包含起点和终点。 我了解如何使用数据及其用途; 我正在苦苦挣扎的是正确读取数据,以便我可以处理它。 我目前有这个:

void directedGraphAnalysis() {
    //Open file, read contents, write to graph
    ifstream file("test2a.txt");
    string data     = ""; //Each line will be read as a string and converted to an int
    int nodeCount   = 0;
    int* matrix     = nullptr;
    int matrixIndex = 0;
    int count       = 0;
    int v1          = INT_MAX;
    int v2          = INT_MAX;

    while (getline(file, data, ',')){
        int x = stoi(data);
        ++count;
        if (count == 1) {
            nodeCount = x;
            matrix = new int[nodeCount * nodeCount];
        }
        else if (count < (nodeCount * nodeCount) - 1) {
            matrix[matrixIndex++] = x;
        }
        else if (v1 == INT_MAX) {
            v1 = x;
        }
        else {
            v2 = x;
        }

        cout << "X: " << x << endl;
    }

    //DirectedGraph graph = DirectedGraph(matrix, nodeCount);
    //graph.displayGraph();

    cout << "ANALYSIS COMPLETE." << endl;
}

此实现似乎使节点数正确,但之后的每一行都会跳过第一个数字,这意味着 v1 和 v2 从未设置,并且矩阵具有与文本文件不匹配的不正确边。 Matrix 只是一个一维数组,表示大小为 nodeCount * nodeCount 的二维矩阵。 我不确定我在做什么导致矩阵填充不当,我也不知道为什么要跳过第一个数字。

因为std::getline只接受单个字符作为分隔符。 如果使用,作为分隔符,则NEW LINE(0x0D, 0x0A)是正常字符。

例如,在第一个,字符之前, std::getline读取:

6
0

并将其转换为

6

那么下一行的第一位数字丢失了。

我尝试修复逻辑如下:

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

void directedGraphAnalysis() {
    //Open file, read contents, write to graph
    ifstream file("test2a.txt");
    string data     = ""; //Each line will be read as a string and converted to an int
    string line     = "";
    int nodeCount   = 0;
    int* matrix     = nullptr;
    int matrixIndex = 0;
    int count       = 0;
    int v1          = INT_MAX;
    int v2          = INT_MAX;

    while (getline(file, line)){
        stringstream stream(line);
        while (getline(stream, data, ',')){
            int x = stoi(data);
            ++count;
            if (count == 1) {
                nodeCount = x;
                matrix = new int[nodeCount * nodeCount];
            }
            else if (count < (nodeCount * nodeCount) - 1) {
                matrix[matrixIndex++] = x;
            }
            else if (v1 == INT_MAX) {
                v1 = x;
            }
            else {
                v2 = x;
            }

            cout << "X: " << x << endl;
        }
    }

    //DirectedGraph graph = DirectedGraph(matrix, nodeCount);
    //graph.displayGraph();

    cout << "ANALYSIS COMPLETE." << endl;
}

int main()
{
    directedGraphAnalysis();
}


您需要分析您的源文件,然后根据需要进行输入操作。

邻接矩阵似乎适用于有向和加权图。 我不清楚它是面向行还是面向列,但这对于 reding 操作并不重要。

那么,我们会看到吗?

  1. 作为无符号整数的维度在其自己的行上
  2. 它遵循具有上述给定维度的矩形矩阵。 行以逗号分隔值的形式给出。 这,我们称之为 CSV。 并且,有很多方法可以将 csv 拆分为其组件:因为使用矩阵是二次的,所以会有维度行。
  3. 最后,我们有和 additionalline,包含 2 个值,起始坐标,用逗号分隔。

根据这些观察,我们将决定如何阅读。

第一行可以简单地读取,使用标准格式的输入函数,使用提取操作符>>. Formatted input >>. Formatted input将始终尝试转换输入数据,直到看到空格(包括换行符 '\\n')。 它不会消耗空白,所以 '\\n')。

可以使用std::getline (未格式化输入)函数将下一行写为整行。 但请注意。 std::getline将读取,直到找到换行符 '\\n'。 请记住,输入流中仍然有一个换行符。 因此,如果您只是调用std::getline ,它将读取一个空字符串,然后使用换行符。 为了解决这个问题,我们可以简单地使用std::ws函数。 这将消耗但不会读取文本前面的所有空白。 所以,我们总是可以这样写: std::getline(file >> std::ws, data); 这将首先调用file >> std::ws然后调用std::getline

好了,这个理论现在应该清楚了。

然后,我们需要创建一个二维数组。 您只是在创建一个一维数组。 这可以通过首先为行创建一个数组,然后为每一行创建额外的列数组来完成。 这我们可以像下面这样:

// allocate memory for rows
int** matrix = new int* [dimension];

// For each row, allocate memory for the columns
for(unsigned int row=0; row < dimension; ++row) 
    matrix[row] = new int [dimension];

现在我们有一个二维数组,我们可以用matrix[row][col];

接下来,因为我们知道维度,我们可以创建一个循环并调用std::getline维度次。

读完一行后,我们需要拆分该行并存储值。 为此,我们将使用一种常用方法,即使用std::istringstreamstd::getline直到看到逗号。

最后,我们读取最后一行并以相同的方式提取开始坐标。

对于每个读取操作,都应添加错误检查。

然后一个示例程序可能如下所示。

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

int main() {

    // Open the file
    std::ifstream fileStream{ "r:\\text2a.txt" };

    // Check, if we could open the file
    if (fileStream) {

        // Read the dimension of the matrix and check for valid input
        unsigned int dimension{};
        if ((fileStream >> dimension) and (dimension > 0)) {

            // Now we haveopened the file and read the dimension
            // Allocate array. Firs,allocate memory for rows
            int** matrix = new int* [dimension];

            // And now, for each row, allocate space for columns
            // Then read the rows with the column values
            for (unsigned int row = 0; row < dimension; ++row) {
                matrix[row] = new int[dimension] {};

                // Read next line from file
                std::string line{};
                if (std::getline(fileStream >> std::ws, line)) {

                    // Put the line into an std::istringstream, so that we can extract the column values
                    std::istringstream iss(line);

                    // Extract all columns
                    for (unsigned int col = 0; col < dimension; ++col) {
                        std::string valueAsString{};
                        if (std::getline(iss, valueAsString, ',')) {
                            matrix[row][col] = std::stoi(valueAsString);
                        }
                        else {
                            // Could not read column value. Show error message
                            std::cerr << "\n\n*** Error. Could not read value at row " << row << ",  column: "<< col << "\n\n";
                        }
                    }
                }
                else {
                    // Could not read row with column values
                    std::cerr << "\n\n*** Error. Could not read row number " << row << "\n\n";
                }
            }
            // Now we have read the matrix. 
            // Get the start point
            unsigned int rowStart{}, columnStart{};
            char comma{};
            if ((fileStream >> rowStart >> comma >> columnStart) and comma == ',') {


                // Now, we have all data
                // Show some debug output
                std::cout << "Adjancency matrix\n\nDimension: " << dimension << "\n\nMatrix:\n\n";

                for (unsigned int row = 0; row < dimension; ++row) {
                    for (unsigned int col = 0; col < dimension; ++col) {
                        std::cout << matrix[row][col] << ' ';
                    }
                    std::cout << '\n';
                }
                std::cout << "\n\nStart point: " << rowStart << ", " << columnStart << '\n';


                // Release all allocated memory
                for (unsigned int row = 0; row < dimension; ++row)
                    delete[] matrix[row];
                delete[] matrix;
            }
            else {
                // Could not read start values
                std::cerr << "\n\nError: Could not read start values\n\n";
            }
        }
        else {
            // Invalid input for dimension of adjacency matrix. Show error message
            std::cerr << "\n\n*** Error. Invalid dimentsion found\n\n";
        }
    }
    else {
        // File could not be opened. Show error message
        std::cerr << "\n\n*** Error. Could not open source file\n\n";
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM