Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read integers elegantly using C++ stream?

Tags:

c++

stream

input

I have a file full of lines in this format:

1 - 2: 3

I want to only load numbers using C++ streams. Whats the most elegant way to do it? I only thought about cin.get() and checikng each char if it is number or not.

like image 860
poiu Avatar asked Jan 22 '11 12:01

poiu


2 Answers

I think this one would be the fastest -yet elegant- way:

int a, b, c;
scanf("%d-%d:%d", &a, &b, &c);
like image 154
semekh Avatar answered Oct 22 '22 16:10

semekh


You can use a locale to change what things are read from the file as it is being read. That is, you will filter out all non-numeric values:

struct numeric_only: std::ctype<char> 
{
    numeric_only(): std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table()
    {
        static std::vector<std::ctype_base::mask> 
            rc(std::ctype<char>::table_size,std::ctype_base::space);

        std::fill(&rc['0'], &rc[':'], std::ctype_base::digit);
        return &rc[0];
    }
};

std::fstream myFile("foo.txt");
myfile.imbue(std::locale(std::locale(), new numeric_only()));

Then when you read your file, it'll convert all non digits to spaces while leaving you only the numbers. After that, you can simply use your normal conversions to transform what is being read into ints.

std::vector<int> intFromFile;
std::istream_iterator<int> myFileIter(myFile);
std::istream_iterator<int> eos;
std::copy(myFileIter, eos, std::back_inserter(intFromFile));

Response to the comments below:

Here is what I did to get it to work

int main(int args, char** argv){
    std::fstream blah;
    blah.open("foo.txt", std::fstream::in);
    if(!blah.is_open()){
        std::cout << "no file";
        return 0;
    }
    blah.imbue(std::locale(std::locale(), new numeric_only()));

    std::vector<int> intFromFile;
    std::istream_iterator<int> myFileIter(blah);
    std::istream_iterator<int> eos;
    std::copy(myFileIter, eos, std::back_inserter(intFromFile));

   return 0;
}

And this put only the ints into the vector, nothing more, nothing less. The reason it wasn't working before was two fold:

  1. I was filling up to '9' but not '9' itself. I've changed the fill to ':'
  2. Numbers larger than what an int can hold are a problem. I'd suggest using longs.
like image 37
wheaties Avatar answered Oct 22 '22 17:10

wheaties