Reputation: 18798
I am new to programming. I have been trying to write a function in C++ that explodes the contents of a string into a string array at a given parameter, example:
string str = "___this_ is__ th_e str__ing we__ will use__";
should return string array:
cout << stringArray[0]; // 'this'
cout << stringArray[1]; // ' is'
cout << stringArray[2]; // ' th'
cout << stringArray[3]; // 'e str'
cout << stringArray[4]; // 'ing we'
cout << stringArray[5]; // ' will use'
I can tokenize the string just fine, but the hardest part for me is how can i specify the number of elements in stringArray before assigning it the current string toke and also how to return stringArray from the function.
Would someone show me how to write the function?
Edit1: I don't necessarily need the results to been in string array just any container that i can call as a regular variable with some sort of indexing.
Upvotes: 16
Views: 78737
Reputation: 264351
Using STL (sorry no compiler not tested)
#include <vector>
#include <string>
#include <sstream>
int main()
{
std::vector<std::string> result;
std::string str = "___this_ is__ th_e str__ing we__ will use__";
std::stringstream data(str);
std::string line;
while(std::getline(data,line,'_'))
{
result.push_back(line); // Note: You may get a couple of blank lines
// When multiple underscores are beside each other.
}
}
// or define a token
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
#include <sstream>
struct Token: public std::string // Yes I know this is nasty.
{ // But it is just to demosntrate the principle.
};
std::istream& operator>>(std::istream& s,Token& t)
{
std::getline(s,t,'_');
// ***
// Remove extra '_' characters from the stream.
char c;
while(s && ((c = s.get()) != '_')) {/*Do Nothing*/}
if (s)
{
s.unget(); // Put back the last char as it is not '_'
}
return s;
}
int main()
{
std::string str = "___this_ is__ th_e str__ing we__ will use__";
std::stringstream data(str);
std::vector<std::string> result(std::istream_iterator<Token>(data),
std::istream_iterator<Token>());
}
Upvotes: 11
Reputation: 2188
# turn a string into a deque based on a delimiter string
bool tolist(deque<string>& list,string basis,const string& cutter) {
bool found = false;
if (!cutter.empty()) {
while (!basis.empty() ) {
string::size_type pos = basis.find(cutter);
if (pos != string::npos) {
found = true;
list.push_back(basis.substr(0, pos)); //pos says 2
basis = basis.substr(pos+cutter.size(),string::npos);
} else {
list.push_back(basis);
basis.clear();
}
}
}
return found;
}
Upvotes: 0
Reputation: 25948
This worked for me:
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
vector<string> split(string str, char delimiter) {
vector<string> internal;
stringstream ss(str); // Turn the string into a stream.
string tok;
while(getline(ss, tok, delimiter)) {
internal.push_back(tok);
}
return internal;
}
int main(int argc, char **argv) {
string myCSV = "one,two,three,four";
vector<string> sep = split(myCSV, ',');
// If using C++11 (which I recommend)
/* for(string t : sep)
* cout << t << endl;
*/
for(int i = 0; i < sep.size(); ++i)
cout << sep[i] << endl;
}
Source: http://code.runnable.com/VHb0hWMZp-ws1gAr/splitting-a-string-into-a-vector-for-c%2B%2B
Upvotes: 0
Reputation: 59
I think that I have wrote a much simpler solution.
std::vector<std::string> explode(const std::string& string, const char delimiter) {
std::vector<std::string> result;
unsigned int start = 0, pos = 0;
while (pos != string.length()) {
if (string.at(pos) == delimiter || pos + 1 == string.length()) {
unsigned int size = (pos - start) + ((pos + 1) == string.length() ? 1 : 0);
if (size != 0) { // Make this 'if' as a option? like a parameter with removeEmptyString?
result.push_back(string.substr(start, size));
}
start = pos + 1;
}
pos++;
}
return std::move(result);
}
Upvotes: 0
Reputation: 3613
Here is my cooked up code (complete). May be it's useful for some with the same need.
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
int main(){
std::string s = "scott:tiger:mushroom";
std::string delimiter = ":";
std::vector<std::string> outputArr;
size_t pos = 0;
std::string token;
while ((pos = s.find(delimiter)) != std::string::npos) {
token = s.substr(0, pos);
s.erase(0, pos + delimiter.length());
outputArr.push_back(token);
}
outputArr.push_back(s);
// Printing Array to see the results
std::cout<<"====================================================================================\n";
for ( int i=0;i<outputArr.size();i++){
std::cout<<outputArr[i]<<"\n";
}
std::cout<<"====================================================================================\n";
}
Cheers!!
Upvotes: 0
Reputation: 1849
Here's my first attempt at this using vectors and strings:
vector<string> explode(const string& str, const char& ch) {
string next;
vector<string> result;
// For each character in the string
for (string::const_iterator it = str.begin(); it != str.end(); it++) {
// If we've hit the terminal character
if (*it == ch) {
// If we have some characters accumulated
if (!next.empty()) {
// Add them to the result vector
result.push_back(next);
next.clear();
}
} else {
// Accumulate the next character into the sequence
next += *it;
}
}
if (!next.empty())
result.push_back(next);
return result;
}
Hopefully this gives you some sort of idea of how to go about this. On your example string it returns the correct results with this test code:
int main (int, char const **) {
std::string blah = "___this_ is__ th_e str__ing we__ will use__";
std::vector<std::string> result = explode(blah, '_');
for (size_t i = 0; i < result.size(); i++) {
cout << "\"" << result[i] << "\"" << endl;
}
return 0;
}
Upvotes: 16
Reputation: 13185
It works for me :
#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector<string> explode( const string &delimiter, const string &explodeme);
int main(int argc, char *argv[])
{
string str = "I have a lovely bunch of cocoa nuts";
cout<<str<<endl;
vector<string> v = explode(" ", str);
for(int i=0; i<v.size(); i++)
cout <<i << " ["<< v[i] <<"] " <<endl;
}
vector<string> explode( const string &delimiter, const string &str)
{
vector<string> arr;
int strleng = str.length();
int delleng = delimiter.length();
if (delleng==0)
return arr;//no change
int i=0;
int k=0;
while( i<strleng )
{
int j=0;
while (i+j<strleng && j<delleng && str[i+j]==delimiter[j])
j++;
if (j==delleng)//found delimiter
{
arr.push_back( str.substr(k, i-k) );
i+=delleng;
k=i;
}
else
{
i++;
}
}
arr.push_back( str.substr(k, i-k) );
return arr;
}
source : http://www.zedwood.com/article/106/cpp-explode-function
Upvotes: 3
Reputation: 1
The code below:
template <typename OutputIterator>
int explode(const string &s, const char c, OutputIterator output) {
stringstream data(s);
string line;
int i=0;
while(std::getline(data,line,c)) { *output++ = line; i++; }
return i;
}
int main(...) {
string test="H:AMBV4:2:182.45:182.45:182.45:182.45:182.41:32:17700:3229365:201008121711:0";
cout << test << endl;
vector<string> event;
**This is the main call**
int evts = explode(test,':', back_inserter(event));
for (int k=0; k<evts; k++)
cout << event[k] << "~";
cout << endl;
}
Outputs
H:AMBV4:2:182.45:182.45:182.45:182.45:182.41:32:17700:3229365:201008121711:0
H~AMBV4~2~182.45~182.45~182.45~182.45~182.41~32~17700~3229365~201008121711~0~
Upvotes: 0
Reputation: 4394
Wait until your data structures class and then code it with a linked list. If it is for homework though, you may be able to get away with just initing the array be very large.
Upvotes: 0
Reputation: 101171
If you insist on making stringArray
an array as oppossed to a std::vector<>
(which would be the right thing to do) you have to either:
Using a vector is easier vector::push_back()
appends new stuff to the end. So:
vector* explode(string s){
vector<string> *v = new vector<string>
//...
// in a loop
v->push_back(string_fragment);
//...
return v;
}
Not needed after all Left in for completeness.
To return the array of strings you use char **
.
As in
char ** explode(const char *in){
...
}
BTW-- How will the calling function know how many elements are in the returned array? You'll have to solve that too. Use std::vector<>
unless you are constrained by outside forces...
Upvotes: 1
Reputation: 2731
Perhaps you should use a list instead of an array. That way you would not need to know the number of elements ahead of time. You may also consider using the STL containers.
Upvotes: 1
Reputation: 25667
Use std::vector as a dynamic array and return that as your result.
Upvotes: 1
Reputation: 2275
You can use a vector of string (std::vector<std::string>
), append each token to it with push_back, and then return it from your tokenize function.
Upvotes: 1