eee
eee

Reputation: 23

Reading line of integers while ignoring incorrect data (c++)

I'm reading input using istringstreams for easy conversion from string to integer. I'm having trouble reading the line when it contains errors, such as "1 45 3 XXXX 45 X", where i want it to simply ignore the letters. Normally, without any errors i would just have done:

string s = "1 2 34 5 6";
istringstream stream(s);
int temp;

cout << s << " -> ";

while(stream >> temp){
    //do something with temp for ex:
    cout << temp << " ";
}

This would give

 "1 2 34 5 6" -> 1 2 34 5 6

Obviously this doesnt work when i have a string of the form "1 45 3 XXXX 45 X" as it would break at XXXX and not continue. But what i would like to get is:

"1 45 3 XXXX 45 X" -> 1 45 3 45

So, i know the problem, but im stuck on how to solve it. I got this feeling there should be a very simple solution to this, but i cant figure it out, and most examples ive searched for online don't take errors in data into account or are too advanced for my needs.

Upvotes: 2

Views: 2196

Answers (5)

vinitha
vinitha

Reputation: 21

Filter alphabets in the string before passing to istringstrem as below

string s = "1 2 34 xxx 5 6"; 
string data;

for (unsigned int i = 0; i < sizeof(s); i++)
{
  if ((std::isdigit(s[i])) || (s[i] = ' '))
  data += s[i];
}
istringstream stream(data); 
cout << data << " -> ";  

Upvotes: 0

Remy Lebeau
Remy Lebeau

Reputation: 596417

If the undesirable text (or better, the desirable integers) is always in the same positions, I would just use sscanf() instead:

std::string s = "1 45 3 XXXX 45 X";
int temp[4] = {0}; 

cout << s << " -> "; 

sscanf(s.c_str(), "%d %d %d %*s %d", &temp[0], &temp[1], &temp[2], &temp[3]);

for(int i = 0; i < 4; ++i)
{ 
    cout << temp[i] << " "; 
} 

Upvotes: 0

Anonymous
Anonymous

Reputation: 18631

If you want to process a string and get everything that seems int-like then try the following approach:

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


int main() {
    std::string s = "1 45 3 XXXX 45 X 11111111111111111111 2.3";
    std::istringstream stream(s);
    int foo;

    while(true) {
        if(stream >> foo) {
            std::cout << foo << std::endl; // do something with the int
        } else if (stream.eof()) {
            break; // We're done
        } else {
            // We've hit a non-int
            stream.clear(); // clear the error flags
            stream.ignore(); // ignore everything till the delimeter
        }
    }
}

Or alternatively a version using exceptions:

int main() {
    std::string s = "1 45 3 XXXX 45 X 11111111111111111111 2.3";
    std::istringstream stream(s);
    stream.exceptions(std::ios::failbit | std::ios::badbit);
    int foo;

    while(!stream.eof()) {
        try {
            stream >> foo;
            std::cout << foo << std::endl;
        } catch (const std::ios::failure & e) {
            stream.clear();
            stream.ignore();
        }
    }
}

Output:

1
45
3
45
2
3

Upvotes: 4

cplusplus
cplusplus

Reputation: 614

Removing anything that isn't a number or whitespace from your string before parsing it solves your problem. Did you consider that?

Something like this should do it.

void filter(string * input) {
    for(int i = 0; i < input->length(); i++) {
        char val = input->at(i);
        if (val != ' ' && !isdigit(val)) {
            // not a valid character
            input->erase(i, 1);
            i--;
        }
    }
}

Upvotes: 1

P.P
P.P

Reputation: 121397

You could simply convert it to C style string and scan through to see if there's at least one non-digit. If so, break & don't print the string.

char *cstr;
bool flag = true;

while(stream >> temp){
    i=0;
    flag = true;
    cstr = new char[temp.size()+1];
    strcpy (cstr, temp.c_str());
    while(cstr[i]) {
     if(!isdigit(cstr[i])) { 
       flag = false;
       break;
     }
    i++;
    }
    if(flag) 
    cout << temp << " ";
}

Not sure if this is the efficient way but my guess is that even with any other library function, you may have to do equivalent scan through in one way or another. So I think this is fine.

Upvotes: 0

Related Questions