Home > Enterprise >  Why I can't read an integer from a stringstream which has some words followed by an integer?
Why I can't read an integer from a stringstream which has some words followed by an integer?

Time:03-02

I am a beginner in C , just want to know why I cannot show the 6.9 in the second line of my output?
Does it seem like I ignore the word 'lady' and then just break the getline while loop and then move to the other line?

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

using namespace std; 


int main() {
    ifstream input("Text.txt");
    ofstream output("Text1.txt");
    string line; 
    while (getline(input, line)) {
        istringstream inputstring(line);
        double result;
        string garbage;
        while (inputstring >> garbage) {
            inputstring.ignore();
            if (inputstring >> result) {
                output << result << endl;
            }
        }
    }
}

This is my content of text.txt

broccoli 2.95  
lady finger 6.9  
Watermelon 10  
Apple 7.8  
Orangw 8.5  

And this is the output

2.95  
10  
7.8  
8.5  

CodePudding user response:

First you read "lady" into garbage, then you ignore the single space character following it, then you try to read "finger" into result, which fails and the stream enters an error state.
Then the loop exits, because the stream is in error.

You need to clear the error state when the number input fails, and you don't need to ignore anything.

while (inputstring >> garbage) {
    if (inputstring >> result) {
        output << result << endl;
    }
    else {
        // This will make the stream re-read the non-number as a string.
        inputstring.clear();
    }
}

CodePudding user response:

You are discovering that input is hard. The problem is that your leading text may have spaces. You don’t know how many.

The correct way of thinking about this is to recognize that the number is always the last item on the line.

If we shift our perspective to that life becomes much, much easier. There are a gazillion ways to split the last item off of a line of text. An easy way would be to just tokenize the line (by splitting on whitespace):

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

int main()
{
  std::istringstream inputstream( R"<>(
    broccoli 2.95
    lady finger 6.9
    Watermelon 10
    Apple 7.8
    Orangw 8.5
  )<>" );
  
  // For each non-blank line:
  std::string line;
  while (getline( inputstream >> std::ws, line ))
  {
    // Tokenize the line and keep only the last token found
    std::istringstream tokenstream( line );
    std::string token;
    while (tokenstream >> token) { }
    
    // The last token should be your number
    try 
    {
      double number = stod( token );
      std::cout << number << "\n";
    }
    catch (...) { }
  }
}

The advantage of thinking of things this way is it is also much less brittle if your input includes duds like:

pi
3.141592
i 8 8 pickles

All this presumes, of course, that you do not care about the text ⟷ number relationship: all that matters is the valid numbers (because you are summing them or some such).

  • Related