简体   繁体   中英

Parsing through text file with C++

I am trying to figure out the best way to read in numbers from a text file and set these numbers to variables. I am having trouble because there will be multiple text files that will be testing my code and they are all of different lengths and sizes. A sample test one looks like this:

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

Where the first number represents a vertex on a graph, the first number in a coordinate is the vertex it is going towards in a directed graph, and the second number is the weight of the edge. I tried doing getline and putting it into arrays but in certain test cases there could be 100 coordinates and I am not sure how to specify array size. I am also having trouble parsing through the parenthesis and comma and am not sure how to initialize the variables with the correct number from the text file.

Parsing shouldn't be that difficult, espacially when you can use std::stringstream to separate all the elements from input. Indeed, you want to remove all the paranthesis first then emplace the elements into the container.

#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';
    }
}

Note that you need C++17 to compile the code. You have to use basic loops instead of ranged-for loops and omit auto if you use an older C++ standard. Also I used a vector of pairs, but it's better if you use a struct / class for nodes, to make the code more maintanable.

I would use something like this:

#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... 
    }
}

This works too.

#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;
}

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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