Вопрос

I am currently working on parsing a file into program memory.

The file to parse looks like this:

    file info
    second line of file info
    date

    # col1    col2    col3    col4   col5      col6      col7    col8     col9   col10    col11     col12     col13     col14  
    firstSetOfElements
    4
           2       1       1       0       3       1       2       3       0 -49.4377        0 0       -26.9356 -24.5221
           3       2       1       0       3       2       4       3       13.7527 -43.2619       0 0       -19.3462 -28.0525
           4       3       1       0       3       4       1       3       14.2459 43.5163       0 0       33.3506 15.2988
           5       4       1       0       3       2       1       4       49.4377 0       0 0       25.0818 38.3082


    # col1      col2      col3      col4      col5      col6
    secondSetOfElements
    1
         1 4 3 4 1 2

What I am trying to do:

    file.open(FILENAME, ios::in); // Open file
    if (file.is_open()) 
    { 
            // Get the line number where "firstSetOfElements" is located. Store the line number.
            // Go to the line after that line, and store the integer listed there as a variable (`int noFirstElems`).
            // (this is the number of rows I will be parsing into the first array).
    // start parsing at the first line of the array (the line under the previous)     
         while (getline(file, firstLineOfFirstSetToParse)) //starting at the first row of data array elements, begin parsing into text file (this I've got handled).
         {
                 //add a row vector until you get to a blank line (which will be after 4 rows of data).
         }

After doing this for the "firstSetOfElements" array, I will then do the same thing to parse the "secondSetOfElements" data into an array, as above.

I have parsed the data just fine, but have not found a resource I can understand for setting begin/end points for the lines I am to parse.

Thanks in advance!

Это было полезно?

Решение

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

string trimmed(string& input)
{
    size_t firstNonWSIdx = input.find_first_not_of(" ");
    size_t lastNonWSIdx = input.find_last_not_of(" ");
    firstNonWSIdx = (firstNonWSIdx == string::npos ? 0 : firstNonWSIdx);
    return input.substr(firstNonWSIdx, lastNonWSIdx);
}

void resetStrStream(istringstream& sstr, string const& newInput)
{
    sstr.clear();
    sstr.str(newInput);
}

void readFile(char const* fileName, vector<vector<float> >& data)
{
    ifstream infile(fileName);
    string input;
    istringstream iss;
    while(infile)
    {
        getline(infile, input);
        string token = trimmed(input);
        if (token.compare("setOfElements") == 0)
        {
            getline(infile, input);
            resetStrStream(iss, trimmed(input));
            int arraySize;
            iss >> arraySize;
            vector<float> values;
            int i = 0;
            while(i++ < arraySize)
            {
                getline(infile, input);
                resetStrStream(iss, trimmed(input));
                float val;
                while (iss >> val)
                {
                   values.push_back(val);
                } 
            }
            data.push_back(values);
        }
    }    
}

void testData(vector<vector<float> >& data)
{
    for (int i = 0; i < data.size(); i++)
    {
        for (int j = 0; j < data[i].size(); j++)
        {
            cout << data[i][j] << " ";
        }
        cout << endl;
    }
}

int main()
{
    vector< vector<float> > data;
    readFile("textfile.txt", data);
    testData(data);
    return 0;
}

Другие советы

The problem based on the way you have described is straightforward to solve: read line by line, scan for a token named "SetOfElements" and treat the next line as the size of your 2D-array, and then read size number of lines and store them into your array.

But, your file's layout is confusing: your comment line (starting with #) says there are going to be 8 columns, but subsequent lines contain 14 columns. Is your program supposed to ignore the last 6 columns? Also, your elements seem to be mixture of ints and floats, unless the columns 1 through 8 are also floats that don't have a fractional part.

If in fact, the data-type is mixed, and columns 1-8 have to read as ints and the remaining as floats, then your parser code is going to be complex otherwise, it should be simple getline... scan line... continue kind of algorithm.

Also, do your set delimiters change? The first set is identified by "firstSetOfElements" and the second set's id is "secondSetOfElements", it would be easier if they simply "SetOfElements", otherwise you would have construct the delimiter string before reading every new set of elements.

This might give you a few ideas:

std::string line;
int line_num = 0;

for (int i = 0; i < 3; ++i)
     assert(getline(input, line))); // ignore 3 lines

while (input >> set_name)
{
    if (set_name == '#') { input.ignore('\n'); continue; }
    std::vector<std::vector<float>>>& set = sets[set_name];
    if (input >> rows)
        for (int i = 0; i < rows && getline(input, line); ++i)
        {
            std::istringstream iss(line);
            set.push_back(std::vector<float>());
            while (iss >> num) set.back().push_back(num);
        }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top