Splitting a string with delimiter in C++


Keywords:c++ 


Question: 

There are a few examples about this question. However most of the answers are not what I am looking for.

I am looking for a way to implement an efficient and easy function rather than using boost or any other non STL libraries. If you ask me why, in most coding competitions and interviews, you are not allowed to use them.

Here is the closest that I can approach:

vector<string> SplitString(const char *str, char c)
{
    vector<string> result;
    do {
        const char *begin = str;
        while(*str != c && *str) {
            str++;
        }
        result.push_back(string(begin, str));
    } while (0 != *str++);
    return result;
}

int main() {

    string mainString = "This is a sentence. Another sentence. The third sentence. This is the last sentence.";
    vector<string> sentences;
    sentences = SplitString(mainString.c_str(), '.');
    while (!sentences.empty()) {
        cout << sentences.back() << endl;
        sentences.pop_back();
    }
    return 0;
}

Now the problem with this is, it can only have a char delimiter not string. I have thought of implementing a few ways but they seemed way too complex. The easiest one that I thought was, convert delimiter to char array use c as the first char of the delimiter char array after this:

while(*str != c && *str) {
    str++;
}
const char *beginDelim = *cArr;
while(1) {
    if (*str == *cArr && *str && *cArr) {
       str++;
       cArr++;
    }
    else if (!*cArr) {
        break;
    }
    else if (*cArr) {
        cArr = beginDelim;
    }
}

And the code continues from result.push_back() part.

So I was wondering if are there any way to implement an efficient and easy function for splitting a string with a string delimiter?


4 Answers: 

Generally speaking, a string is a char pointer. So you should search for the first character in the delimeter, then check the very next character. Also in looking at your code I am not sure that while (0 != *str++) is doing what you think it is. I think you mean for it to be null terminated.

 

something like this should do it:

vector<string> SplitString(const char* str,const char* d) {
  vector<string> result;
  size_t len = strlen(d);
  const char* start = str;
  while ( str = strstr(start,d) ) {
    result.push_back(string(start,len));
    start = str + len;
  }
  result.push_back(start);
  return result;
}
 

How's this:

#include <vector>
#include <algorithm>
#include <string>

using namespace std;

vector<string> SplitString(const string &str, const string &delim)
{
    vector<string> ret;
    string::const_iterator prev = str.begin();

    for (string::const_iterator i = str.begin(); i < str.end() - delim.length()+1; ++i)
    {
        if (equal(delim.begin(), delim.end(), i)) {
            ret.push_back(string(prev,i));
            i += delim.length()-1;
            prev = i+1;
        }
    }

    ret.push_back(string(prev,str.end()));

    return ret;
}
 
#include <iostream>
#include <string>
#include <vector>

using namespace std;

vector<string> SplitString(string str, const string &delim) {
    vector<string> result;
    size_t found;
    while((found = str.find(delim)) != string::npos) {
        result.push_back(str.substr(0, found));
        str = str.substr(found + delim.size());
    }
    return result;
}

int main() {
    string mainString = "This is a sentence. Another sentence. The third sentence. This is the last sentence.";
    vector<string> sentences;

    sentences = SplitString(mainString, ".");

    for(auto& sentence : sentences) {
        cout << sentence << endl;   
    }
    return 0;
}