使用C ++解析文本文件

时间:2017-09-17 06:44:21

标签: c++ parsing text-files

我试图找出从文本文件中读取数字的最佳方法,并将这些数字设置为变量。我遇到了麻烦,因为会有多个文本文件将测试我的代码,它们都有不同的长度和大小。样本测试看起来像这样:

0 (1,3) (3,5)
1 (2,6)
2 (4,2)
3 (1,1) (2,4) (4,6)
4 (0,3) (2,7)

如果第一个数字表示图形上的顶点,则坐标中的第一个数字是它在有向图中所朝向的顶点,第二个数字是边缘的权重。我尝试使用getline并将其放入数组中,但在某些测试用例中可能有100个坐标,我不知道如何指定数组大小。我也无法通过括号和逗号进行解析,并且不确定如何使用文本文件中的正确数字初始化变量。

3 个答案:

答案 0 :(得分:0)

当您可以使用std::stringstream将所有元素与输入分开时,解析不应该是那么困难。实际上,您希望首先删除所有的paranthesis然后将元素放入容器中。

#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include <cctype>

int main()
{
    std::ifstream read("file.txt");

    std::vector<std::vector<std::pair<int, int>>> graph;

    // read until you reach the end of the file
    for (std::string line; std::getline(read, line); ) {

        // removing punctuation like paranthesis, commas, etc.
        std::replace_if(std::begin(line), std::end(line), [] (char x) { return std::ispunct(x); }, ' ');

        // inserting the line into a stream that helps us parse the content
        std::stringstream ss(line);

        // read the node number
        int source, destination, weight;
        ss >> source;

        // create a new vector for the new node, so you can place all it's destinations / weights in it
        graph.insert(std::next(std::begin(graph), source), {{}});

        // read the dests / weights until you reach the end of the current line
        while (ss >> destination >> weight)
            graph[source].emplace_back(destination, weight);
    }

    read.close();
    std::ofstream write("output.txt");

    for (const auto node : graph) {
        for (const auto [dest, weight] : node)
            write << "(" << dest << ", " << weight << ") ";
        write << '\n';
    }
}

请注意,您需要C ++ 17来编译代码。如果使用较旧的C ++标准,则必须使用基本循环而不是ranged-for loops并省略auto。我还使用了一对对矢量,但如果你对节点使用结构/类,那么它会更好,以使代码更具可维护性。

答案 1 :(得分:0)

我会用这样的东西:

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

struct coordinate
{
    int vertex;
    int weight;
};

struct vertex_set
{
    int vertex;
    std::vector<coordinate> coordinates;
};

std::istream& operator>>(std::istream &in, coordinate &out)
{
    char ch1, ch2, ch3;
    if (in >> ch1 >> out.to_vertex >> ch2 >> out.weight >> ch3)
    {
        if ((ch1 != '(') || (ch2 != ',') || (ch3 != ')'))
            in.setstate(std::ios_base::failbit);
    }
    return in;
}

std::istream& operator>>(std::istream &in, std::vector<coordinate> &out)
{
    out.clear();
    coordinate coord;
    while (in >> coord)
        out.push_back(coord);
    return in;
}

std::istream& operator>>(std::istream &in, vertex_set &out)
{
    return in >> out.vertex >> out.coordinates;
}

std::ifstream f("file.txt");
std::string line;

while (std::getline(f, line))
{
    vertex_set vs;
    if (std::istringstream(line) >> vs)
    {
        // use vs.vertex and vs.coordinates as needed... 
    }
}

答案 2 :(得分:0)

这也有效。

#include<iostream>
#include<sstream>
#include<string>
using namespace std;
int main() {
    int vertices[1000][3], qv = 0;  //use number more than 1000 if it is required
    while (cin) {
        int n;
        char c;
        string s;
        getline(cin, s);
        istringstream is(s);
        is >> n;
        is >> c;
        while (c == '(') {
            vertices[qv][0] = n;
            is >> vertices[qv][1];
            is >> c;   //,
            is >> vertices[qv++][2];
            is >> c;   //)
            is >> c;   //(
        }
    }
    for (int i = 0; i < qv; i++) //unified view
        cout << vertices[i][0] << ' ' << vertices[i][1] << ' ' << vertices[i][2] << endl;
    for (int i = 0; i < qv; i++) {  //initial view
        cout << vertices[i][0];
        cout << " (" << vertices[i][1] << "," << vertices[i][2] << ")";
        while (i + 1 < qv && vertices[i][0] == vertices[i + 1][0]) {
            i++;
            cout << " (" << vertices[i][1] << "," << vertices[i][2] << ")";
    }
    cout << endl;
}

}