1

I wanted to know how I can grab numbers out of a string in C++. I'm getting the string from an input and will be getting multiple lines, but I already have the line reading working. Note: the lines always have an even number of ints

Here's what I'd like the code to look something like:

std::getline(std::cin, line);// line looks something like "10 3 40 45 8 12"
int a, b;
while(!line.empty() /*line still has ints to extract*/) {
    a = someMethod(line);//gets first int.  So, 10 first loop, 40 second, 8 third
    b = someMethod(line);//gets second int. So, 3 first loop, 45 second, 12 third
    myMethod(a,b);//a method from elsewhere in my code.  It's here so you know that I need both a and b
}

Anything similar would help. Thank you very much!

Wolf
  • 9,679
  • 7
  • 62
  • 108
  • How about `std::stringstream`? – The Paramagnetic Croissant Jun 02 '14 at 04:07
  • How could I use stringstream for this? I'm only a little familiar with it. – user2670028 Jun 02 '14 at 04:11
  • @user2670028: You'd construct it from `line` and then use it in just the same way as you'd extract integers from `std::cin`. The library is nicely orthogonal this way. However, there are things to watch out for - see [How to parse a string to an int in C++](http://stackoverflow.com/questions/194465/how-to-parse-a-string-to-an-int-in-c). – Simon Jun 02 '14 at 04:14
  • @Simon I think I've come up with a way that will work using this idea, thanks! – user2670028 Jun 02 '14 at 04:25
  • Did you do any research before asking here. This has so many answers, just search: parse space delimited numbers c++ and google has many many solutions. – Fantastic Mr Fox Jun 02 '14 at 04:41

4 Answers4

3

Here is a complete example.

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


int main(){
    std::string line = "2 4 56 6";
    std::stringstream stream(line);
    int i;
    while (stream >> i) {
        std::cout << i << std::endl;
    }
}

The following works fine also, so reading multiple lines should not be a problem.

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


int main(){
    std::string line = "2 4 56 6";
    std::stringstream stream(line);
    int i;
    while (stream >> i) {
        std::cout << i << std::endl;
    }

    line =  "32 62 44 6 22 58 34 60 71 86";
    stream.clear();
    stream.str(line);
    int a,b;
    while(stream >> a && stream >> b){ 
        std::cout << a << " " << b << "\n";
    }
}
merlin2011
  • 71,677
  • 44
  • 195
  • 329
  • `while(!stream.eof())` is broken - `eof` isn't set until after a read operation fails - it doesn't promise that the next read will not fail (how could it - it doesn't know what you'll try to read yet). You should use `while (stream >> i)` directly. – Tony Delroy Jun 02 '14 at 04:36
  • @TonyD, Fair point, fixed. – merlin2011 Jun 02 '14 at 04:37
  • @merlin2011 thanks, this is a lot like what I've created based on another comment. The only thing missing (which I guess wasn't entirely specified inthe question, sorry) is that I need the stringstream to work for the next line as well. Do I have to create a new stringstream or do you know how to grab the next version of "line"? – user2670028 Jun 02 '14 at 04:49
  • 1
    @user2670028, You should be able to reuse it by doing `stream.clear()` followed by `stream.str(line)`. – merlin2011 Jun 02 '14 at 04:56
  • @merlin2011 I'm core dumping at the end. My Code: `while(stream >> a && stream >> b){ cout << a << " " << b << "\n"; myMethod(a,b); }` output with line "32 62 44 6 22 58 34 60 71 86": 32 62 44 66 22 58 34 60 Segmentation fault BTW thanks for all your help. I can probably figure this out on my own now but I still got this error. – user2670028 Jun 02 '14 at 05:11
  • @user2670028, Testing. Also, is this on a subsequent line? – merlin2011 Jun 02 '14 at 05:13
  • @user2670028, Could not reproduce. I assume the accept means you figured out that the segfault was in `myMethod(a,b);`? – merlin2011 Jun 02 '14 at 05:16
  • @Merlin2011 You mean is there code around it? Yeah. I'm thinking it's probably something about my code that isn't present here, but I don't know why it would be having a seg fault during the loop if that was the case. Thanks for your help again – user2670028 Jun 02 '14 at 05:17
  • @user2670028, I assume it is in your other code. I just updated with an example of reading multiple lines, reusing the `stringstream`. – merlin2011 Jun 02 '14 at 05:18
  • @merlin2011 I know myMethod works. I don't know why this isn't working. I use this strategy a few times in my code and it worked for at least one of them, so I accepted your answer. No idea why it isn't working at this spot. I assume it has something to do with my code and that you can't help me without seeing my actual code. Thanks for your help a lot. I'll try to figure this out on my own if I can. Thank you!! – user2670028 Jun 02 '14 at 05:20
  • @user2670028 so, do you have `std::string line; std::stringstream stream; while (std::cin >> line) { stream.str(line); while (stream >> aa >> b) { cout...; myMethod(a,b); } stream.clear(); }`? It shouldn't segfault - though we can't see your `myMethod` to see if it has bugs. – Tony Delroy Jun 02 '14 at 05:33
  • @Merlin2011 Thank you so much for your help, my code is working fine and has been for a while. I thought myMethod was working as intended because I used a lot of tests on it but it did have a very rare error that happened to exist for the particular input that gave the seg fault. I thought the error was somewhere in my code and it was. Thank you for all your help!! – user2670028 Jun 02 '14 at 06:27
  • @user2670028, Glad it worked it for you. :) – merlin2011 Jun 02 '14 at 06:29
  • @TonyD Yes, the error was a very rare case in myMethod. I stated that I thought myMethod worked fine, but I also said the error was probably somewhere in my code. Thanks a lot for trying to help though! My code is working fine and has been for a while now. – user2670028 Jun 02 '14 at 06:29
0

You can do like this:

string line;
getline(std::cin, line);// line looks something like "10 3 40 45 8 12"
int a,  b;

vector<string> tokens;
istringstream iss(line);

copy(istream_iterator<string>(iss), 
     istream_iterator<string>(),
     back_inserter<vector<string> >(tokens));

stringstream s;
for (int i=0;i<tokens.size()/2;i++)
{   
  s<< tokens[i];
  s>>a;
  s.clear();
  s<<tokens[i+2];
  s>>b;
  s.clear();
  myMethod(a,b);
}
Rakib
  • 7,435
  • 7
  • 29
  • 45
0

Get tokens from string line and use them as you want.

#include <iostream>
#include <string>
#include <boost/tokenizer.hpp>

using namespace std;

typedef boost::tokenizer<boost::char_separator<char> >
    tokenizer;


void myMethod(int a, int b)
{
    cout<<a<<" "<<b<<endl;
}

void getNumber(string line)
{            
    boost::char_separator<char> sep(" ");
    tokenizer tokens(line, sep);    
    string evenStr, oddStr;

    for(tokenizer::iterator iterToken=tokens.begin();
          iterToken != tokens.end(); ++iterToken)
    {
        evenStr = *iterToken;                       
        ++iterToken;
        if(iterToken != tokens.end())
        {
            oddStr = *iterToken;                                   
        myMethod(atoi(evenStr.c_str()), atoi(oddStr.c_str()));
        }        
    }    
}

int main()
{
   string line("10 3 40 45 8 12");
   getNumber(line);

   return 0;
}
Nik
  • 1,294
  • 10
  • 16
0

There are multiple ways to achieve this. I prefer to use boost.

Example:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>

int main()
{
    std::string line = "10 3 40 45 8 12 9"; //std::getline(std::cin, line);// line looks something like "10 3 40 45 8 12"

    std::vector<std::string> intNumbers;
    std::string s;
    boost::split(intNumbers, line, boost::is_any_of(" "), boost::token_compress_on);

    unsigned int i=0;
    while(i < intNumbers.size())
    {
        try{
            int a = boost::lexical_cast<int>(intNumbers[i++]);

            if(i >= intNumbers.size())
            {
                std::cout << "invlaid values" << std::endl;
                break;
            }
            int b = boost::lexical_cast<int>(intNumbers[i++]);

            std::cout << "value a: " << a << std::endl;
            std::cout << "value b: " << b << std::endl;

            std::cout << "my method (multiply) a*b: " << (a*b) << std::endl;
        }
        catch(boost::bad_lexical_cast &e)
        {
            std::cout << "invlaid values" << std::endl;
        }
    }
}
Ankit Patel
  • 1,191
  • 1
  • 9
  • 9