开发者

C++: Check istream has non-space, non-tab, non-newline characters left without extracting chars

开发者 https://www.devze.com 2023-02-09 08:56 出处:网络
I am reading a std::istream and I need to verify without extracting characters that: The stream is not "empty", i.e. that trying to read a char will not result in an fail state (solved by u

I am reading a std::istream and I need to verify without extracting characters that:

  1. The stream is not "empty", i.e. that trying to read a char will not result in an fail state (solved by using peek() member function and checking fail state, then setting back to original state)

  2. That among the characters left there is at least one which is not a space, a tab or a newline char.

The reason for this is, is that I am reading text files containing say one int per line, and sometimes there may be extra spaces / new-lines at the end of the file and this causes issues when I try get back the data from the file to a vector of int.

A peek(int n) would proba开发者_开发技巧bly do what I need but I am stuck with its implementation. I know I could just read istream like:

while (myInt << myIstream) {…} //Will fail when I am at the end 

but the same check would fail for a number of different conditions (say I have something which is not an int on some line) and being able to differentiate between the two reading errors (unexpected thing, nothing left) would help me to write more robust code, as I could write:

while (something_left(myIstream)) {
  myInt << myIstream;
  if (myStream.fail()) {…} //Horrible things happened
}

Thank you!


There is a function called ws which eats whitespace. Perhaps you could call that after each read. If that hits eof, then you know you've got a normal termination. If it doesn't and the next read doesn't produce a valid int, then you know you've got garbage in your file. Maybe something like:

#include <fstream>
#include <iostream>

int main()
{
    std::ifstream infile("test.dat");
    while (infile)
    {
        int i;
        infile >> i;
        if (!infile.fail())
            std::cout << i << '\n';
        else
            std::cout << "garbage\n";
        ws(infile);
    }
}


this is what I did to skip whitespace/detect EOF before the actual input:

char c;
if (!(cin >> c)) //skip whitespace
    return false;  // EOF or other error
cin.unget();

This is independent of what data you are going to read.

This code relies on the skipws manipulator being set by default for standard streams, but it can be set manually cin >> skipw >> c;


And simple

for(;;){
  if(!(myIstream >> myInt)){
    if(myIstream.eof()) {
     //end of file
    }else{
     //not an integer
    }
  }

  // Do something with myInt
}

does not work? Why you need to know if there are numbers left?

Edit Changed to Ben's proposition.


The usual way to handle this situation is not to avoid reading from the stream, but to put back characters, which have been read, if needed:

int get_int(std::istream& in)
{
    int n = 0;
    while(true) {
        if (in >> n)
            return n;
        clean_input(in);
    }
}

void clean_input(std::istream& in)
{
    if (in.fail()) {
        in.clear();

        // throw away (skip) pending characters in input 
        // which are non-digits
        char ch;
        while (in >> ch) {
            if (isdigit(ch)) {
                // stuff digit back into the stream
                in.unget();
                return;
            }
        }
    }
    error("No input");    // eof or bad
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号