# Splitting a string

This topic is 4246 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I'm reading in a text file which is in the format of 1,0,0,1,0, etc.... each line I read is stored in a string. I am new to c++ and am really not sure how to split each the string so that each number is an entry in an array. What I'm trying to accomplish would be that for the string "1,0,0,1,0" I would have an array like this: nums[0] would be 1 nums[1] would be 0 nums[2] would be 0 nums[3] would be 1 nums[4] would be 0 Something like the c# string.split function would be good. Thanks for any help.

##### Share on other sites
not a very efficient way but it should work (haven't tested out)

vector SplitString(const string& str,char separator){
string::size_type lastpos=0,pos=0;
vector ret;
do{
pos=str.find(separator,lastpos+1);
ret.push_back(str.substr(lastpos,pos-lastpos));
lastpos=pos;
}while(pos!=string::npos);
return ret;
}

##### Share on other sites
sorry slight problem

vector<string> SplitString(const string& str,char separator){
string::size_type lastpos=0,pos=0;
vector ret;
do{
pos=str.find(separator,lastpos+1);
ret.push_back(str.substr(lastpos,pos-lastpos));
lastpos=pos;
}while(pos!=string::npos);
return ret;
}

##### Share on other sites
forgot the other one now :P
vector<string> SplitString(const string& str,char separator){
string::size_type lastpos=0,pos=0;
vector<string> ret;
do{
pos=str.find(separator,lastpos+1);
ret.push_back(str.substr(lastpos,pos-lastpos));
lastpos=pos;
}while(pos!=string::npos);
return ret;
}

##### Share on other sites
Thank you, but I must be doing something wrong because it isn't working.

vector<string> v;v = SplitString(line,',');for(int u = 0;u < v.size();u++){cout << v.at(u) ;}cout << endl;

Surely what is printed should have no commas in it, but I get it with commas

"0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
..."

Shouldn't each entry in v not have a comma, but just a number?

##### Share on other sites
Try changing the line
lastpos = pos;
to
lastpos = pos + 1;

May be then you'll have to check for 'lastpos' non going greater or equal than 'str.size()' inside the loop. It depends on the way 'find' method handles the situation.

##### Share on other sites
If it's always going to be numbers this should work:

#include <vector>#include <iostream>void readNumbers(std::istream& in, std::vector<int>& numbers){    int num;    in >> num;    while(in.good())    {        numbers.push_back(num);        int >> "," >> num;    }}

And if not, give boost::tokenizer a try

#include <vector>#include <string>#include <iterator>#include <boost/tokenizer.hpp>void parseNumbers(const std::string& str, std::vector<std::string>& numbers){   boost::char_separator<char> sep(",");   boost::tokenizer< boost::char_separator<char> > tok(str, sep);   std::copy(tok.begin(), tok.end(), std::back_inserter(numbers));}

##### Share on other sites
int counter = 0;for(int i = 0; i < reader.size(); i++){    if(reader != ",")    {        Nums[counter] = reader;        counter++;    }}

that will work if you only plan on 1 digit numbers

##### Share on other sites
Wow, lots of strange ideas here.

OP, you probably want to do the parsing directly as you read the file, instead. The code I will show does handle errors, by reading comma-delimited items into strings (which should always succeed until EOF) and then extracting integers out of those. Trying to parse out commas after the fact is probably more complex than is needed.

That said, if this is a file format you control, and you don't need error checking, then *don't use commas to separate the numbers*. Use whitespace instead. The C++ library streams are highly oriented towards reading whitespace-delimited things.

AP, whywhat got the problem :) This is still pretty ugly stuff to do by hand though. I assume Boost provides something... (in StringAlgo perhaps?)

joanusdmentia, I assume reading from "int" rather than "in" is a typo, but regardless, reading into a string literal like that definitely doesn't do what you want. Also, please get over the silly fear of returning container objects. The pass-non-const-reference approach really only makes sense when you need to return something else anyway, because:

- You can really only get a performance advantage when the caller already had a container sitting around for some reason
- Otherwise, the caller has to jump through more hoops in order to use the function
- And if the caller *did* have that vector, you have to decide if its contents should be cleared first, and if so, on which side.

raptorstrike, you need to compare to ',' rather than "," since you're iterating over characters, and anyway, the ascii value != the numeric value.

#include <vector>#include <iostream>#include <string>#include <sstream>std::vector<int> readNumbers(std::istream& in) {  std::string token;  std::vector<int> result;  while (std::getline(in, token, ',')) {    int x;    char garbage;    std::stringstream parser(in);    if ((parser >> x) && (parser >> std::ws) && !(parser >> garbage)) {      // if you don't care if there's extra stuff after the number in that      // field, just use 'parser >> x'.      result.push_back(x);    } else {      // error handling here as desired    }  }}

##### Share on other sites
Quote:
 Original post by Zahlmanjoanusdmentia, I assume reading from "int" rather than "in" is a typo, but regardless, reading into a string literal like that definitely doesn't do what you want.

Yep, typo. I probably should've tried that code out before posting it, admittadly I haven't really iostreams for parsing before. I was *expecting* the istream to try and read the literal and if the stream contents doesn't match to fail, I guess that that's not the case though [smile]

Quote:
 Original post by ZahlmanAlso, please get over the silly fear of returning container objects. The pass-non-const-reference approach really only makes sense when you need to return something else anyway, because:- You can really only get a performance advantage when the caller already had a container sitting around for some reason- Otherwise, the caller has to jump through more hoops in order to use the function- And if the caller *did* have that vector, you have to decide if its contents should be cleared first, and if so, on which side.

Good points, it's more a habit than anything else. Would NVRO work with a complex object such as std::vector? Not that performance matters in this case, but there are situations where you really don't want a temporary std::vector of several 1000 objects being constructed.

##### Share on other sites
Quote:
Original post by joanusdmentia
Quote:
 Original post by Zahlmanjoanusdmentia, I assume reading from "int" rather than "in" is a typo, but regardless, reading into a string literal like that definitely doesn't do what you want.

Yep, typo. I probably should've tried that code out before posting it, admittadly I haven't really iostreams for parsing before. I was *expecting* the istream to try and read the literal and if the stream contents doesn't match to fail, I guess that that's not the case though [smile]

Wishful thinking :) The string literal is, after all, a char*, so it would try to read a word into the memory where that string literal is. Which is already undefined for writing to static storage, and re-undefined :) if the word happens to be longer than the existing string literal.

But you could always make a wrapper class that behaved in that way. Something like:

class expected_input_literal {  char* literal; // weak; do not delete!  public:  expected_input_literal(char* literal): literal(literal) {}    friend istream& operator>>(istream& is, const expected_input_literal& eil) {    char c;    char* s = eil.literal;    while (is >> c && *s) {      if (c != *s++) {        is.setstate(ios_base::failbit);      }    }  }};

Quote:
 Good points, it's more a habit than anything else. Would NVRO work with a complex object such as std::vector? Not that performance matters in this case, but there are situations where you really don't want a temporary std::vector of several 1000 objects being constructed.

As far as I can figure out in my head, NRVO isn't really any harder to implement on complex types: it's still just an aliasing of a particular variable to the return value. What *would* make it harder (and/or impossible) would be if multiple exit points used different variables, or if a more complex expression were returned.

##### Share on other sites
Forgive my ignorance, but what is NVRO?

##### Share on other sites
Quote:
 Original post by jflangloisForgive my ignorance, but what is NVRO?
Named return value optimization.

##### Share on other sites
Ah, so it should be NRVO (edit: which is how Zahlman spelled it, my bad), which does yield somthing in google. Thanks.

##### Share on other sites
Quote:
 Original post by jflangloisAh, so it should be NRVO (edit: which is how Zahlman spelled, my bad), which does yield somthing in google. Thanks.
Oops, I didn't even notice that the letters were transposed :)

##### Share on other sites
Apparently, nor did joanusdmentia, but I forgive easily. Thanks again.

##### Share on other sites
Quote:
 Original post by ZahlmanAs far as I can figure out in my head, NRVO isn't really any harder to implement on complex types: it's still just an aliasing of a particular variable to the return value. What *would* make it harder (and/or impossible) would be if multiple exit points used different variables, or if a more complex expression were returned.

I was thinking in terms of global effects (common example being incrementing a static int in the constructor). A bit of googling revealed though that temporary is allowed to be eliminated even if there are global side-effects.

Quote:
 Original post by jflangloisApparently, nor did joanusdmentia, but I forgive easily. Thanks again.

Heh, I'll blame it on typlexia [smile]