UnboxTheCat
UnboxTheCat

Reputation: 33

how to read and parse text files with istringstream?

I am trying to read a .txt file line by line:

vector<vector<int>> iVecGrid;
vector<int> iVecRow;

ifstream text;
text.open("grid.txt", ios::in);

if (!text)
{
    cout << "Error!\n";
    return EXIT_FAILURE;
}

istringstream isLine;
string sLine;
while (getline(text, sLine))
{
    isLine.str(sLine);
    int iNumber;
    while (isLine >> iNumber)
    {
        cout << iNumber << " ";
        iVecRow.push_back(iNumber);
    }
    cout << endl;

    iVecGrid.push_back(iVecRow);
    iVecRow.clear();
}

When I put isLine inside the while (getline(text, sLine)) loop, it works fine.

But when I put it outside, it bugged out for some reason.

.txt file:

08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48

Upvotes: 0

Views: 202

Answers (2)

R Sahu
R Sahu

Reputation: 206557

When you are done with the following loop

while (isLine >> iNumber)
{
    cout << iNumber << " ";
    iVecRow.push_back(iNumber);
}

isLine is in a state of error. The error state needs to cleared. Add the following line after the loop.

isLine.clear();

Also, the position of isLine needs to be reset to point to the start of the string. You can use the following line for that.

isLine.seekg(0);

Both of these problems are avoided by moving the scope of isLine to inside the while block.

The following should work.

while (getline(text, sLine))
{
    isLine.str(sLine);
    isLine.seekg(0);   //ADD. Start reading from position 0.

    int iNumber;
    while (isLine >> iNumber)
    {
        cout << iNumber << " ";
        iVecRow.push_back(iNumber);
    }

    isLine.clear();  //ADD. Clear the error state.

    cout << endl;

    iVecGrid.push_back(iVecRow);
    iVecRow.clear();
}

However, I would recommend sticking to your first approach. It removes the unnecessary clutter from your code.

while (getline(text, sLine))
{
    std::istringstream isLine(sLine);

    int iNumber;
    while (isLine >> iNumber)
    {
        cout << iNumber << " ";
        iVecRow.push_back(iNumber);
    }

    cout << endl;

    iVecGrid.push_back(iVecRow);
    iVecRow.clear();
}

Upvotes: 4

NathanOliver
NathanOliver

Reputation: 180415

When you do

while (isLine >> iNumber)
{
    cout << iNumber << " ";
    iVecRow.push_back(iNumber);
}

the loop runs until isLine enters a failed state. Once it enters that failed state, you can no longer read from it until you call the clear member function to clear those errors. This means that when isLine is declare outside of the while loop, the first iteration of the loop puts it into an error state, and it stays that way for each subsequent iteration since you do not manually clear the errors.

On the other hand, when isLine is declared inside the while loop, it is destroyed at the end of the loop and created again at the start of the next iteration. This process gives you a new stream that is not in a error state so you can use it as expected.

Upvotes: 3

Related Questions