How to parse table of numbers in C++

1.7k views Asked by At

I need to parse a table of numbers formatted as ascii text. There are 36 space delimited signed integers per line of text and about 3000 lines in the file. The input file is generated by me in Matlab so I could modify the format. On the other hand, I also want to be able to parse the same file in VHDL and so ascii text is about the only format possible.

So far, I have a little program like this that can loop through all the lines of the input file. I just haven't found a way to get individual numbers out of the line. I am not a C++ purest. I would consider fscanf() but 36 numbers is a bit much for that. Please suggest practical ways to get numbers out of a text file.

int main()
{
    string line;
    ifstream myfile("CorrOut.dat");
    if (!myfile.is_open())
        cout << "Unable to open file";
    else{
        while (getline(myfile, line))
        {
            cout << line << '\n';
        }
        myfile.close();
    }
    return 0;
}
2

There are 2 answers

0
PaulMcKenzie On BEST ANSWER

Use std::istringstream. Here is an example:

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

using namespace std;

int main()
{
    string line;
    istringstream strm;
    int num;
    ifstream ifs("YourData");
    while (getline(ifs, line))
    {
        istringstream strm(line);
        while ( strm >> num )
           cout << num << " ";
        cout << "\n";
    }
}

Live Example

If you want to create a table, use a std::vector or other suitable container:

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

using namespace std;

int main()
{
    string line;

    // our 2 dimensional table
    vector<vector<int>> table;

    istringstream strm;
    int num;
    ifstream ifs("YourData");
    while (getline(ifs, line))
    {
        vector<int> vInt;
        istringstream strm(line);
        while ( strm >> num )
           vInt.push_back(num);
        table.push_back(vInt);
    }
}

The table vector gets populated, row by row. Note we created an intermediate vector to store each row, and then that row gets added to the table.

Live Example

0
A B On

You can use a few different approaches, the one offered above is probable the quickest of them, however in case you have different delimitation characters you may consider one of the following solutions:

The first solution, read strings line by line. After that it use the find function in order to find the first position o the specific delimiter. It then removes the number read and continues till the delimiter is not found anymore. You can customize the delimiter by modifying the delimiter variable value.

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

using namespace std;

int main()
{
    string line;
    ifstream myfile("CorrOut.dat");
    string delimiter = " ";
    size_t pos = 0;
    string token;

    vector<vector<int>> data;

    if (!myfile.is_open())
        cout << "Unable to open file";
    else {
        while (getline(myfile, line))
        {
            vector<int> temp;
            pos = 0;
            while ((pos = line.find(delimiter)) != std::string::npos) {
                token = line.substr(0, pos);
                std::cout << token << std::endl;
                line.erase(0, pos + delimiter.length());
                temp.push_back(atoi(token.c_str()));
            }
            data.push_back(temp);
        }
        myfile.close();
    }
    return 0;
}

The second solution make use of regex and it doesn't care about the delimiter use, it will search and match any integers found in the string.

#include <iostream>
#include <string>
#include <regex> // The new library introduced in C++ 11
#include <fstream>

using namespace std;

int main()
{
    string line;
    ifstream myfile("CorrOut.dat");
    std::smatch m;
    std::regex e("[-+]?\\d+");

    vector<vector<int>> data;

    if (!myfile.is_open())
        cout << "Unable to open file";
    else {
        while (getline(myfile, line))
        {
            vector<int> temp;
            while (regex_search(line, m, e)) {
                for (auto x : m) {
                    std::cout << x.str() << " ";
                    temp.push_back(atoi(x.str().c_str()));
                }
                std::cout << std::endl;

                line = m.suffix().str();
            }

            data.push_back(temp);
        }
        myfile.close();
    }
    return 0;
}