Splitting a string

Started by
16 comments, last by joanusdmentia 17 years, 9 months ago
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.
Advertisement
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;
}
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;
}
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;
}
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?
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.
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));}
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V
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
____________________________"This just in, 9 out of 10 americans agree that 1 out of 10 americans will disagree with the other 9"- Colin Mochrie
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    }  }}
Quote:Original post by Zahlman
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.


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 Zahlman
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.


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.
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V

This topic is closed to new replies.

Advertisement