644

I am parsing a string in C++ using the following:

using namespace std;

string parsed,input="text to be parsed";
stringstream input_stringstream(input);

if (getline(input_stringstream,parsed,' '))
{
     // do some processing.
}

Parsing with a single char delimiter is fine. But what if I want to use a string as delimiter.

Example: I want to split:

scott>=tiger

with >= as delimiter so that I can get scott and tiger.

plasmacel
  • 8,183
  • 7
  • 53
  • 101
TheCrazyProgrammer
  • 7,918
  • 8
  • 25
  • 41
  • 6
    https://stackoverflow.blog/2019/10/11/c-creator-bjarne-stroustrup-answers-our-top-five-c-questions scroll down to #5. – Wais Kamal Mar 06 '21 at 07:40
  • see this [question](https://stackoverflow.com/questions/68439991/read-file-and-split-and-trim-each-line-with-cpp20) implement reading files and splitting strings with c++20. – AmirSalar Jul 19 '21 at 21:01
  • @WaisKamal: you could have linked to https://stackoverflow.com/questions/236129/how-do-i-iterate-over-the-words-of-a-string directly – Thomas Weller Oct 17 '22 at 16:53

35 Answers35

950

You can use the std::string::find() function to find the position of your string delimiter, then use std::string::substr() to get a token.

Example:

std::string s = "scott>=tiger";
std::string delimiter = ">=";
std::string token = s.substr(0, s.find(delimiter)); // token is "scott"
  • The find(const string& str, size_t pos = 0) function returns the position of the first occurrence of str in the string, or npos if the string is not found.

  • The substr(size_t pos = 0, size_t n = npos) function returns a substring of the object, starting at position pos and of length npos.


If you have multiple delimiters, after you have extracted one token, you can remove it (delimiter included) to proceed with subsequent extractions (if you want to preserve the original string, just use s = s.substr(pos + delimiter.length());):

s.erase(0, s.find(delimiter) + delimiter.length());

This way you can easily loop to get each token.

Complete Example

std::string s = "scott>=tiger>=mushroom";
std::string delimiter = ">=";

size_t pos = 0;
std::string token;
while ((pos = s.find(delimiter)) != std::string::npos) {
    token = s.substr(0, pos);
    std::cout << token << std::endl;
    s.erase(0, pos + delimiter.length());
}
std::cout << s << std::endl;

Output:

scott
tiger
mushroom
Vincenzo Pii
  • 18,961
  • 8
  • 39
  • 49
  • 144
    For those who don't want to modify the input string, do `size_t last = 0; size_t next = 0; while ((next = s.find(delimiter, last)) != string::npos) { cout << s.substr(last, next-last) << endl; last = next + 1; } cout << s.substr(last) << endl;` – Hayk Martiros Jan 31 '15 at 05:07
  • 57
    NOTE: `mushroom` outputs outside of the loop, i.e. `s = mushroom` – Don Larynx Jan 31 '15 at 22:22
  • 2
    Those samples does not extract the last token from string. A sample of mine extracting an IpV4 from one string: size_t last = 0; size_t next = 0; int index = 0; while (index<4) { next = str.find(delimiter, last); auto number = str.substr(last, next - last); IPv4[index++] = atoi(number.c_str()); last = next + 1; } – rfog Aug 17 '15 at 08:00
  • 4
    @hayk.mart Just a note, that would be the following, you need add 2 not 1 due to the size of the delimiter which is 2 characters :) : std::string s = "scott>=tiger>=mushroom"; std::string delimiter = ">="; size_t last = 0; size_t next = 0; while ((next = s.find(delimiter, last)) != std::string::npos) { std::cout << s.substr(last, next-last) << std::endl; last = next + 2; } std::cout << s.substr(last) << std::endl; – ervinbosenbacher Oct 30 '15 at 12:52
  • In order to get "tiger", use `std::string token = s.substr(s.find(delimiter) + 1);`, if you are sure that it exists (I use +1 in the length)... – gsamaras Apr 02 '19 at 16:45
  • Hi, I am using the code posted by @Vincenzo Pii, and it works fine, the only problem I have, is that I cant get the last word of my sentence. Anyone that resolved this problem? – Jonathan Prieto May 10 '20 at 14:37
  • This answer is wrong, if fail to handle the last one – Alen Wesker Jul 17 '20 at 03:44
  • 23
    Wondering how many of the 615 upvoters missed the last line and are running hidden bugs in their production code. Judging from the comments, I'd wager at least a handful. IMO this answer would be much better suited if it didn't use `cout` and instead showed it as a function. – Qix - MONICA WAS MISTREATED Sep 09 '20 at 08:47
  • 2
    FYI, npos in the while-loop means no position (or end of the string) – Tan Nguyen Sep 12 '21 at 09:25
  • 1
    For performance: [I think](https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c#comment134898905_14267455) – Кое Кто Jun 19 '23 at 16:06
147

For string delimiter

Split string based on a string delimiter. Such as splitting string "adsf-+qwret-+nvfkbdsj-+orthdfjgh-+dfjrleih" based on string delimiter "-+", output will be {"adsf", "qwret", "nvfkbdsj", "orthdfjgh", "dfjrleih"}

#include <iostream>
#include <sstream>
#include <vector>

// for string delimiter
std::vector<std::string> split(std::string s, std::string delimiter) {
    size_t pos_start = 0, pos_end, delim_len = delimiter.length();
    std::string token;
    std::vector<std::string> res;

    while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos) {
        token = s.substr (pos_start, pos_end - pos_start);
        pos_start = pos_end + delim_len;
        res.push_back (token);
    }

    res.push_back (s.substr (pos_start));
    return res;
}

int main() {
    std::string str = "adsf-+qwret-+nvfkbdsj-+orthdfjgh-+dfjrleih";
    std::string delimiter = "-+";
    std::vector<std::string> v = split (str, delimiter);

    for (auto i : v) cout << i << endl;

    return 0;
}

**Output**
adsf
qwret
nvfkbdsj
orthdfjgh
dfjrleih




For single character delimiter

Split string based on a character delimiter. For example, splitting string "adsf+qwer+poui+fdgh" with delimiter "+" will output {"adsf", "qwer", "poui", "fdgh"}

#include <iostream>
#include <sstream>
#include <vector>

std::vector<std::string> split (const std::string &s, char delim) {
    std::vector<std::string> result;
    std::stringstream ss (s);
    std::string item;

    while (getline (ss, item, delim)) {
        result.push_back (item);
    }

    return result;
}

int main() {
    std::string str = "adsf+qwer+poui+fdgh";
    std::vector<std::string> v = split (str, '+');

    for (auto i : v) cout << i << endl;

    return 0;
}

**Output**
adsf
qwer
poui
fdgh
Quonux
  • 2,975
  • 1
  • 24
  • 32
Arafat Hasan
  • 2,811
  • 3
  • 21
  • 38
  • You are returning `vector` I think it'll call copy constructor. – Mayur Nov 27 '18 at 08:21
  • 7
    Every reference I've seen shows that the call to the copy constructor is eliminated in that context. – David Given Jan 12 '19 at 09:50
  • 1
    With "modern" (C++03?) compilers I believe this is correct, RVO and/or move semantics will eliminate the copy constructor. – Kevin Mar 13 '19 at 14:09
  • 3
    I tried the one for single character delimiter, and if the string ends in a delimiter (i.e., an empty csv column at the end of the line), it does not return the empty string. It simply returns one fewer string. For example: 1,2,3,4\nA,B,C, – kounoupis Mar 26 '19 at 01:42
  • 3
    I also tried the one for string delimiter, and if the string ends in a delimiter, the last delimiter becomes part of the last string extracted. – kounoupis Mar 26 '19 at 01:44
129

This method uses std::string::find without mutating the original string by remembering the beginning and end of the previous substring token.

#include <iostream>
#include <string>

int main()
{
    std::string s = "scott>=tiger";
    std::string delim = ">=";

    auto start = 0U;
    auto end = s.find(delim);
    while (end != std::string::npos)
    {
        std::cout << s.substr(start, end - start) << std::endl;
        start = end + delim.length();
        end = s.find(delim, start);
    }

    std::cout << s.substr(start, end);
}
moswald
  • 11,491
  • 7
  • 52
  • 78
  • How do I perform this operation on vector where both strings in the vector are of same form and have same delimiters. I just want to output both strings parsed out in the same way as this works for one string. My "string delim" will remain same ofcourse – Areeb Muzaffar Mar 16 '21 at 21:48
  • Shouldn't the last line rather be `s.substr(start, end - start)` ? I guess this only works as `start + end > size()` and as such it always takes [the rest of the string](https://en.cppreference.com/w/cpp/string/basic_string/substr) ... – Jonas Wilms Sep 12 '21 at 11:10
  • 1
    Since `end == std::string::npos`, it means we want to return the final token. – moswald Sep 12 '21 at 15:34
  • 2
    The last line can be further simplified to ```s.substr(start) ``` with no need to specify the length because it will extract the entire trainling substring if we omit the length. – Peng Dec 25 '21 at 17:05
  • You could move `end = s.find(delim, start)` into the `while` condition. – Steve Ward Nov 10 '22 at 00:24
  • It seems to me that you can replace `substr` with `std::string_view(s.begin()+start, s.begin() + end - start)` for performance, if you use a supporting version of C++. – Кое Кто Jun 19 '23 at 15:58
62

You can use next function to split string:

vector<string> split(const string& str, const string& delim)
{
    vector<string> tokens;
    size_t prev = 0, pos = 0;
    do
    {
        pos = str.find(delim, prev);
        if (pos == string::npos) pos = str.length();
        string token = str.substr(prev, pos-prev);
        if (!token.empty()) tokens.push_back(token);
        prev = pos + delim.length();
    }
    while (pos < str.length() && prev < str.length());
    return tokens;
}
Sviatoslav
  • 753
  • 5
  • 4
  • 12
    IMO it does't work as expected: `split("abc","a")` will return a vector or a single string, `"bc"`, where I think it would make more sense if it had returned a vector of elements `["", "bc"]`. Using `str.split()` in Python, it was intuitive to me that it should return an empty string in case `delim` was found either at the beginning or in the end, but that's just my opinion. Anyway, I just think it should be mentioned – kyriakosSt Nov 30 '18 at 18:26
  • 5
    Would strongly recommend removing the `if (!token.empty()) ` prevent the issue mentioned by @kyriakosSt as well as other issues related to consecutive delimiters. – Steve Mar 12 '19 at 16:33
  • 1
    I would remove my upvote if I could, but SO won't let me. The issue brought up by @kyriakosSt is a problem, and removing `if (!token.empty())` does not seem to suffice to fix it. – bhaller Nov 21 '19 at 00:22
  • 2
    @bhaller this sniplet was designed exactly to skip empty fragments. If you need to keep empty ones I'm afraid you need to write another split implementation. Kindly suggest you to post it here for the good of comunity. – Sviatoslav Feb 26 '20 at 21:28
46

A way of doing it with C++20:

#include <iostream>
#include <ranges>
#include <string_view>

int main()
{
    std::string hello = "text to be parsed";
    auto split = hello
        | std::ranges::views::split(' ')
        | std::ranges::views::transform([](auto&& str) { return std::string_view(&*str.begin(), std::ranges::distance(str)); });

    for (auto&& word : split)
    {
        std::cout << word << std::endl;
    }
}

See:
https://stackoverflow.com/a/48403210/10771848
https://en.cppreference.com/w/cpp/ranges/split_view

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Nox
  • 713
  • 7
  • 16
  • 9
    oh wow. That's a bit complicated. – Patrick Bassut Apr 27 '22 at 12:43
  • For gcc you seem to need version 10 or newer, for Clang it does not even work with the latest release as of now (15), however the current trunk version works. See http://godbolt.org/z/a6fEGYo16 . Might be this issue in clang: https://github.com/llvm/llvm-project/issues/52696. – Zitrax Oct 20 '22 at 12:05
  • Simple things done complicated :) Common Lisp (with cl-ppcre library): `(defvar *delimiters* (cl-ppcre:create-scanner " ")) (cl-ppcre:split *delimiters* "lets see if it works")`. But some like it complicated :) – BitTickler Dec 12 '22 at 03:53
  • 1
    Thankfully C++23 makes adds a constructor overload for `std::string_view` to make this simpler. – Matt Eding Jul 23 '23 at 16:34
43

You can also use regex for this:

std::vector<std::string> split(const std::string str, const std::string regex_str)
{
    std::regex regexz(regex_str);
    std::vector<std::string> list(std::sregex_token_iterator(str.begin(), str.end(), regexz, -1),
                                  std::sregex_token_iterator());
    return list;
}

which is equivalent to :

std::vector<std::string> split(const std::string str, const std::string regex_str)
{
    std::sregex_token_iterator token_iter(str.begin(), str.end(), regexz, -1);
    std::sregex_token_iterator end;
    std::vector<std::string> list;
    while (token_iter != end)
    {
        list.emplace_back(*token_iter++);
    }
    return list;
}

and use it like this :

#include <iostream>
#include <string>
#include <regex>

std::vector<std::string> split(const std::string str,
                               const std::string regex_str) {
    std::regex regexz(regex_str);
    return {std::sregex_token_iterator(str.begin(), str.end(), regexz, -1),
            std::sregex_token_iterator()};
}

int main()
{
    std::string input_str = "lets split this";
    std::string regex_str = " "; 
    auto tokens = split(input_str, regex_str);
    for (auto& item: tokens)
    {
        std::cout<<item <<std::endl;
    }
}

play with it online!

you can simply use substrings, characters, etc like normal, or use actual regular expressions to do the splitting.
its also concise and C++11!

Hossein
  • 24,202
  • 35
  • 119
  • 224
  • 2
    This should be the correct answer, provided C++11 is on the table, which if it isn't...you should be using C++>=11, it's a game-changer! – DeusXMachina Jan 08 '21 at 21:47
  • Please can you explain the return statement in the function `split()`? I am trying to figure how the tokens are pushed into the `std::vector` container. Thanks. – BFamz Feb 03 '21 at 13:53
  • 8
    @DeusXMachina: a fine solution, certainly. One caveat: the "yet more concise form!" in the last code segment will not compile with _LIBCPP_STD_VER > 11, as the method is marked as "delete"... but the earlier code segments that don't implicitly require rvalue reference && compile and run fine under C++2a. – pob Mar 25 '21 at 04:19
  • This seems to be slow for large cases. Very nice otherwise. – Tom Sirgedas Jun 03 '21 at 17:49
  • I would recommend `std::string regex_str= "\\s+"` to avoid empty strings when encountering multiple spaces in a sequence. – PLG Aug 13 '22 at 20:55
22

This code splits lines from text, and add everyone into a vector.

vector<string> split(char *phrase, string delimiter){
    vector<string> list;
    string s = string(phrase);
    size_t pos = 0;
    string token;
    while ((pos = s.find(delimiter)) != string::npos) {
        token = s.substr(0, pos);
        list.push_back(token);
        s.erase(0, pos + delimiter.length());
    }
    list.push_back(s);
    return list;
}

Called by:

vector<string> listFilesMax = split(buffer, "\n");
fret
  • 1,542
  • 21
  • 36
  • it's working great! I've added list.push_back(s); because it was missing. – Stoica Mircea May 25 '18 at 11:51
  • 1
    it misses out the last part of the string. After the while loop ends, we need to add the remaining of s as a new token. – whihathac Jun 01 '18 at 03:00
  • I've made an edit to the code sample to fix the missing push_back. – fret Nov 14 '18 at 01:25
  • 1
    It will be more nicer `vector split(char *phrase, const string delimiter="\n")` – Mayur May 17 '19 at 09:28
  • I know kinda late but, it would work much better if this if statement was added before push `if (token != "") list.push_back(token);` to prevent appending empty strings. – Oliver Tworkowski Jul 16 '20 at 21:37
  • 1
    @OliverTworkowski A lot of the time, what is viewed as being the "correct" behaviour involves leaving the empty strings in. Of course, this may be undesirable in your use case, in which case your suggestion is completely valid. – squ1dd13 Nov 11 '20 at 17:39
19

strtok allows you to pass in multiple chars as delimiters. I bet if you passed in ">=" your example string would be split correctly (even though the > and = are counted as individual delimiters).

EDIT if you don't want to use c_str() to convert from string to char*, you can use substr and find_first_of to tokenize.

string token, mystring("scott>=tiger");
while(token != mystring){
  token = mystring.substr(0,mystring.find_first_of(">="));
  mystring = mystring.substr(mystring.find_first_of(">=") + 1);
  printf("%s ",token.c_str());
}
ryanbwork
  • 2,123
  • 12
  • 12
  • 3
    Thanks. But I want to use only C++ and not any C functions like `strtok()` as it would require me to use char array instead of string. – TheCrazyProgrammer Jan 10 '13 at 19:26
  • 2
    @TheCrazyProgrammer So? If a C function does what you need, use it. This isn't a world where C functions aren't available in C++ (in fact, they have to be). `.c_str()` is cheap and easy, too. – Qix - MONICA WAS MISTREATED Oct 14 '16 at 04:00
  • 1
    The check for if(token != mystring) gives wrong results if you have repeating elements in your string. I used your code to make a version that does not have this. It has many changes that change the answer fundamentally, so I wrote my own answer instead of editing. Check it below. – Amber Elferink Aug 28 '19 at 16:06
19

Answer is already there, but selected-answer uses erase function which is very costly, think of some very big string(in MBs). Therefore I use below function.

vector<string> split(const string& str, const string& delim)
{
    vector<string> result;
    size_t start = 0;

    for (size_t found = str.find(delim); found != string::npos; found = str.find(delim, start))
    {
        result.emplace_back(str.begin() + start, str.begin() + found);
        start = found + delim.size();
    }
    if (start != str.size())
        result.emplace_back(str.begin() + start, str.end());
    return result;      
}
Shubham Agrawal
  • 559
  • 6
  • 15
  • 1
    I tested this, and it works. Thanks! In my opinion, this is the best answer because as the original answer-er states, this solution reduces the memory overhead, and the result is conveniently stored in a vector. (replicates the Python `string.split()` method.) – Robbie Capps Apr 28 '20 at 17:32
  • A nice improvement would be to use `emplace_back()` rather than `push_back(string(...))` – jezza Aug 15 '22 at 10:33
  • @jezza Honoured. – Shubham Agrawal Aug 18 '22 at 11:13
  • You can remove the explicit call to the string constructor too. `emplace_back()` forwards its arguments to the constructor so you can just write `result.emplace_back(i_str.begin()+startIndex, i_str.begin()+found);`. – jezza Aug 19 '22 at 09:30
  • @jezza Done.... – Shubham Agrawal Sep 21 '22 at 15:03
  • You could move `found = i_str.find(i_delim, startIndex)` to within the `while` condition to avoid calling `find` in 2 places. – Steve Ward Nov 10 '22 at 04:22
6

I would use boost::tokenizer. Here's documentation explaining how to make an appropriate tokenizer function: http://www.boost.org/doc/libs/1_52_0/libs/tokenizer/tokenizerfunction.htm

Here's one that works for your case.

struct my_tokenizer_func
{
    template<typename It>
    bool operator()(It& next, It end, std::string & tok)
    {
        if (next == end)
            return false;
        char const * del = ">=";
        auto pos = std::search(next, end, del, del + 2);
        tok.assign(next, pos);
        next = pos;
        if (next != end)
            std::advance(next, 2);
        return true;
    }

    void reset() {}
};

int main()
{
    std::string to_be_parsed = "1) one>=2) two>=3) three>=4) four";
    for (auto i : boost::tokenizer<my_tokenizer_func>(to_be_parsed))
        std::cout << i << '\n';
}
Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
5

Here's my take on this. It handles the edge cases and takes an optional parameter to remove empty entries from the results.

bool endsWith(const std::string& s, const std::string& suffix)
{
    return s.size() >= suffix.size() &&
           s.substr(s.size() - suffix.size()) == suffix;
}

std::vector<std::string> split(const std::string& s, const std::string& delimiter, const bool removeEmptyEntries = false)
{
    std::vector<std::string> tokens;

    for (size_t start = 0, end; start < s.length(); start = end + delimiter.length())
    {
         size_t position = s.find(delimiter, start);
         end = position != std::string::npos ? position : s.length();

         std::string token = s.substr(start, end - start);
         if (!removeEmptyEntries || !token.empty())
         {
             tokens.push_back(token);
         }
    }

    if (!removeEmptyEntries &&
        (s.empty() || endsWith(s, delimiter)))
    {
        tokens.push_back("");
    }

    return tokens;
}

Examples

split("a-b-c", "-"); // [3]("a","b","c")

split("a--c", "-"); // [3]("a","","c")

split("-b-", "-"); // [3]("","b","")

split("--c--", "-"); // [5]("","","c","","")

split("--c--", "-", true); // [1]("c")

split("a", "-"); // [1]("a")

split("", "-"); // [1]("")

split("", "-", true); // [0]()
Steve Ward
  • 486
  • 4
  • 11
Beder Acosta Borges
  • 5,238
  • 2
  • 28
  • 23
  • C++ 20 added the `ends_with` member function to `std::string`. https://en.cppreference.com/w/cpp/string/basic_string/ends_with – Steve Ward Nov 10 '22 at 02:46
5

This should work perfectly for string (or single character) delimiters. Don't forget to include #include <sstream>.

std::string input = "Alfa=,+Bravo=,+Charlie=,+Delta";
std::string delimiter = "=,+"; 
std::istringstream ss(input);
std::string token;
std::string::iterator it;

while(std::getline(ss, token, *(it = delimiter.begin()))) {
    std::cout << token << std::endl; // Token is extracted using '='
    it++;
    // Skip the rest of delimiter if exists ",+"
    while(it != delimiter.end() and ss.peek() == *(it)) { 
        it++; ss.get(); 
    }
}

The first while loop extracts a token using the first character of the string delimiter. The second while loop skips the rest of the delimiter and stops at the beginning of the next token.

hmofrad
  • 1,784
  • 2
  • 22
  • 28
  • This is incorrect. If the input is modified as below, it would split using the first =, when it is not supposed to: `std::string input = "Alfa=,+Bravo=,+Charlie=,+Delta=Echo";` – Amitoj Mar 09 '21 at 07:27
  • @Amitoj Good catch. I revised my answer to even cover inputs with malformed delimiters. – hmofrad Mar 09 '21 at 16:09
5

A very simple/naive approach:

vector<string> words_seperate(string s){
    vector<string> ans;
    string w="";
    for(auto i:s){
        if(i==' '){
           ans.push_back(w);
           w="";
        }
        else{
           w+=i;
        }
    }
    ans.push_back(w);
    return ans;
}

Or you can use boost library split function:

vector<string> result; 
boost::split(result, input, boost::is_any_of("\t"));

Or You can try TOKEN or strtok:

char str[] = "DELIMIT-ME-C++"; 
char *token = strtok(str, "-"); 
while (token) 
{ 
    cout<<token; 
    token = strtok(NULL, "-"); 
} 

Or You can do this:

char split_with=' ';
vector<string> words;
string token; 
stringstream ss(our_string);
while(getline(ss , token , split_with)) words.push_back(token);
5

Just in case in the future, someone wants out of the box function of Vincenzo Pii 's answer

#include <vector>
#include <string>


std::vector<std::string> SplitString(
    std::string str,
    std::string delimeter)
{
    std::vector<std::string> splittedStrings = {};
    size_t pos = 0;

    while ((pos = str.find(delimeter)) != std::string::npos)
    {
        std::string token = str.substr(0, pos);
        if (token.length() > 0)
            splittedStrings.push_back(token);
        str.erase(0, pos + delimeter.length());
    }

    if (str.length() > 0)
        splittedStrings.push_back(str);
    return splittedStrings;
}

I also fixed some bugs so that the function won't return an empty string if there is a delimiter at the start or the end of the string

KuhakuPixel
  • 212
  • 2
  • 4
  • 11
3

This is a complete method that splits the string on any delimiter and returns a vector of the chopped up strings.

It is an adaptation from the answer from ryanbwork. However, his check for: if(token != mystring) gives wrong results if you have repeating elements in your string. This is my solution to that problem.

vector<string> Split(string mystring, string delimiter)
{
    vector<string> subStringList;
    string token;
    while (true)
    {
        size_t findfirst = mystring.find(delimiter);
        if (findfirst == string::npos) //find returns npos if it couldn't find the delimiter anymore
        {
            subStringList.push_back(mystring); //push back the final piece of mystring
            return subStringList;
        }
        token = mystring.substr(0, mystring.find(delimiter));
        mystring = mystring.substr(mystring.find(delimiter) + delimiter.size());
        subStringList.push_back(token);
    }
    return subStringList;
}
Amber Elferink
  • 132
  • 1
  • 10
  • 2
    Something like `while (true)` is usually scary to see in a piece of code like this. Personally I'd recommend rewriting this so that the comparison to `std::string::npos` (or respectively a check against `mystring.size()`) makes the `while (true)` obsolete. – Joel Bodenmann Dec 04 '19 at 16:58
  • 1
    It's inefficient to repeatedly assign `mystring`. You can pass a starting index to `find_first_of`. Also, you're calling `find_first_of` _3_ times every iteration. – Steve Ward Nov 10 '22 at 02:44
  • I'm not sure it works properly with multicharacter delimiters. Because `find_first_of ` : "Finds the first character equal to **one of** the characters in the given character sequence." – Кое Кто Jun 19 '23 at 17:19
  • 1
    I think you are right @КоеКто. I adjusted and tested the code with some basic examples to work for multiple delimiters. – Amber Elferink Jun 20 '23 at 20:13
3

I make this solution. It is very simple, all the prints/values are in the loop (no need to check after the loop).

#include <iostream>
#include <string>

using std::cout;
using std::string;

int main() {
    string s = "it-+is-+working!";
    string d = "-+";

    int firstFindI = 0;
    int secendFindI = 0;
    while (secendFindI != string::npos)
    {
        secendFindI = s.find(d, firstFindI);
        cout << s.substr(firstFindI, secendFindI - firstFindI) << "\n"; // print sliced part
        firstFindI = secendFindI + d.size(); // add to the search index
    }
}

Thanks to @SteveWard for improving this answer.

jacob galam
  • 781
  • 9
  • 21
3

This is similar to other answers but it's using string_view. So these are just views for the original string. Similar to the c++20 example. Though this would be a c++17 example. (edit to skip empty matches)

#include <algorithm>
#include <iostream>
#include <string_view>
#include <vector>
std::vector<std::string_view> split(std::string_view buffer,
                                    const std::string_view delimeter = " ") {
  std::vector<std::string_view> ret{};
  std::decay_t<decltype(std::string_view::npos)> pos{};
  while ((pos = buffer.find(delimeter)) != std::string_view::npos) {
    const auto match = buffer.substr(0, pos);
    if (!match.empty()) ret.push_back(match);
    buffer = buffer.substr(pos + delimeter.size());
  }
  if (!buffer.empty()) ret.push_back(buffer);
  return ret;
}
int main() {
  const auto split_values = split("1 2 3 4 5 6 7 8 9     10 ");
  std::for_each(split_values.begin(), split_values.end(),
                [](const auto& str) { std::cout << str << '\n'; });
  return split_values.size();
}
  • You passed `buffer` by value, so the string_views in the vector refer to a temporary object. – Steve Ward Nov 10 '22 at 00:07
  • Yea that is the point of string_views. If you let the original value go poof then it points to garbage. In the example I'm using a string literal. So that will always exist for the life of the program. You would use std::string instead if you want to make permanent copies. I'm only using std::vector here because I don't know how many results we're gonna get. Maybe there is a std view we could use in c++23 so we can get the result in a more lazy fashion. – Robert Russell Nov 11 '22 at 02:12
  • @SteveWard. I think it's OK , but only for string literals, as in this example. Because such literals actually are not temporary but pretty static constant. I agree that temporary strings for string_view are suspicious for dangling. – Кое Кто Jun 19 '23 at 17:26
2

Since this is the top-rated Stack Overflow Google search result for C++ split string or similar, I'll post a complete, copy/paste runnable example that shows both methods.

splitString uses stringstream (probably the better and easier option in most cases)

splitString2 uses find and substr (a more manual approach)

// SplitString.cpp

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

// function prototypes
std::vector<std::string> splitString(const std::string& str, char delim);
std::vector<std::string> splitString2(const std::string& str, char delim);
std::string getSubstring(const std::string& str, int leftIdx, int rightIdx);


int main(void)
{
  // Test cases - all will pass
  
  std::string str = "ab,cd,ef";
  //std::string str = "abcdef";
  //std::string str = "";
  //std::string str = ",cd,ef";
  //std::string str = "ab,cd,";   // behavior of splitString and splitString2 is different for this final case only, if this case matters to you choose which one you need as applicable
  
  
  std::vector<std::string> tokens = splitString(str, ',');
  
  std::cout << "tokens: " << "\n";
  
  if (tokens.empty())
  {
    std::cout << "(tokens is empty)" << "\n";
  }
  else
  {
    for (auto& token : tokens)
    {
      if (token == "") std::cout << "(empty string)" << "\n";
      else std::cout << token << "\n";
    }
  }
    
  return 0;
}

std::vector<std::string> splitString(const std::string& str, char delim)
{
  std::vector<std::string> tokens;
  
  if (str == "") return tokens;
  
  std::string currentToken;
  
  std::stringstream ss(str);
  
  while (std::getline(ss, currentToken, delim))
  {
    tokens.push_back(currentToken);
  }
  
  return tokens;
}

std::vector<std::string> splitString2(const std::string& str, char delim)
{
  std::vector<std::string> tokens;
  
  if (str == "") return tokens;
  
  int leftIdx = 0;
  
  int delimIdx = str.find(delim);
  
  int rightIdx;
  
  while (delimIdx != std::string::npos)
  {
    rightIdx = delimIdx - 1;
    
    std::string token = getSubstring(str, leftIdx, rightIdx);
    tokens.push_back(token);
    
    // prep for next time around
    leftIdx = delimIdx + 1;
    
    delimIdx = str.find(delim, delimIdx + 1);
  }
  
  rightIdx = str.size() - 1;
  
  std::string token = getSubstring(str, leftIdx, rightIdx);
  tokens.push_back(token);
  
  return tokens;
}

std::string getSubstring(const std::string& str, int leftIdx, int rightIdx)
{
  return str.substr(leftIdx, rightIdx - leftIdx + 1);
}
cdahms
  • 3,402
  • 10
  • 49
  • 75
2

Yet another answer: Here I'm using find_first_not_of string function which returns the position of the first character that does not match any of the characters specified in the delim.

size_t find_first_not_of(const string& delim, size_t pos = 0) const noexcept;

Example:

int main()
{
    size_t start = 0, end = 0;
    std::string str = "scott>=tiger>=cat";
    std::string delim = ">=";
    while ((start = str.find_first_not_of(delim, end)) != std::string::npos)
    {
        end = str.find(delim, start); // finds the 'first' occurance from the 'start'
        std::cout << str.substr(start, end - start)<<std::endl; // extract substring
    }
    return 0;
}

Output:

    scott
    tiger
    cat
SridharKritha
  • 8,481
  • 2
  • 52
  • 43
1

If you do not want to modify the string (as in the answer by Vincenzo Pii) and want to output the last token as well, you may want to use this approach:

inline std::vector<std::string> splitString( const std::string &s, const std::string &delimiter ){
    std::vector<std::string> ret;
    size_t start = 0;
    size_t end = 0;
    size_t len = 0;
    std::string token;
    do{ end = s.find(delimiter,start); 
        len = end - start;
        token = s.substr(start, len);
        ret.emplace_back( token );
        start += len + delimiter.length();
        std::cout << token << std::endl;
    }while ( end != std::string::npos );
    return ret;
}
user2366975
  • 4,350
  • 9
  • 47
  • 87
1

Here's a concise split function. I decided to have back to back delimiters return as an empty string but you could easily check that if the substring is empty and not add it to the vector if it is.

#include <vector>
#include <string>
using namespace std;



vector<string> split(string to_split, string delimiter) {
    size_t pos = 0;
    vector<string> matches{};
    do {
        pos = to_split.find(delimiter);
        int change_end;
        if (pos == string::npos) {
            pos = to_split.length() - 1;
            change_end = 1;
        }
        else {
            change_end = 0;
        }
        matches.push_back(to_split.substr(0, pos+change_end));
        
        to_split.erase(0, pos+1);

    }
    while (!to_split.empty());
    return matches;

}
JadeSpy
  • 140
  • 1
  • 8
1

This method use string find and string substr

vector<string> split(const string& str,const string delim){
vector<string> vtokens; 
size_t start = 0;
size_t end = 0;
while((end = str.find(delim,start))!=string::npos){
    vtokens.push_back(str.substr(start,end-start));
    start = end +1;
}
vtokens.push_back(str.substr(start));
return vtokens;
}
kfc
  • 567
  • 1
  • 5
  • 10
0
#include<iostream>
#include<algorithm>
using namespace std;

int split_count(string str,char delimit){
return count(str.begin(),str.end(),delimit);
}

void split(string str,char delimit,string res[]){
int a=0,i=0;
while(a<str.size()){
res[i]=str.substr(a,str.find(delimit));
a+=res[i].size()+1;
i++;
}
}

int main(){

string a="abc.xyz.mno.def";
int x=split_count(a,'.')+1;
string res[x];
split(a,'.',res);

for(int i=0;i<x;i++)
cout<<res[i]<<endl;
  return 0;
}

P.S: Works only if the lengths of the strings after splitting are equal

0

Function:

std::vector<std::string> WSJCppCore::split(const std::string& sWhat, const std::string& sDelim) {
    std::vector<std::string> vRet;
    size_t nPos = 0;
    size_t nLen = sWhat.length();
    size_t nDelimLen = sDelim.length();
    while (nPos < nLen) {
        std::size_t nFoundPos = sWhat.find(sDelim, nPos);
        if (nFoundPos != std::string::npos) {
            std::string sToken = sWhat.substr(nPos, nFoundPos - nPos);
            vRet.push_back(sToken);
            nPos = nFoundPos + nDelimLen;
            if (nFoundPos + nDelimLen == nLen) { // last delimiter
                vRet.push_back("");
            }
        } else {
            std::string sToken = sWhat.substr(nPos, nLen - nPos);
            vRet.push_back(sToken);
            break;
        }
    }
    return vRet;
}

Unit-tests:

bool UnitTestSplit::run() {
bool bTestSuccess = true;

    struct LTest {
        LTest(
            const std::string &sStr,
            const std::string &sDelim,
            const std::vector<std::string> &vExpectedVector
        ) {
            this->sStr = sStr;
            this->sDelim = sDelim;
            this->vExpectedVector = vExpectedVector;
        };
        std::string sStr;
        std::string sDelim;
        std::vector<std::string> vExpectedVector;
    };
    std::vector<LTest> tests;
    tests.push_back(LTest("1 2 3 4 5", " ", {"1", "2", "3", "4", "5"}));
    tests.push_back(LTest("|1f|2п|3%^|44354|5kdasjfdre|2", "|", {"", "1f", "2п", "3%^", "44354", "5kdasjfdre", "2"}));
    tests.push_back(LTest("|1f|2п|3%^|44354|5kdasjfdre|", "|", {"", "1f", "2п", "3%^", "44354", "5kdasjfdre", ""}));
    tests.push_back(LTest("some1 => some2 => some3", "=>", {"some1 ", " some2 ", " some3"}));
    tests.push_back(LTest("some1 => some2 => some3 =>", "=>", {"some1 ", " some2 ", " some3 ", ""}));

    for (int i = 0; i < tests.size(); i++) {
        LTest test = tests[i];
        std::string sPrefix = "test" + std::to_string(i) + "(\"" + test.sStr + "\")";
        std::vector<std::string> vSplitted = WSJCppCore::split(test.sStr, test.sDelim);
        compareN(bTestSuccess, sPrefix + ": size", vSplitted.size(), test.vExpectedVector.size());
        int nMin = std::min(vSplitted.size(), test.vExpectedVector.size());
        for (int n = 0; n < nMin; n++) {
            compareS(bTestSuccess, sPrefix + ", element: " + std::to_string(n), vSplitted[n], test.vExpectedVector[n]);
        }
    }

    return bTestSuccess;
}
Marc Dirven
  • 309
  • 2
  • 18
sea-kg
  • 317
  • 2
  • 5
0
std::vector<std::string> parse(std::string str,std::string delim){
    std::vector<std::string> tokens;
    char *str_c = strdup(str.c_str()); 
    char* token = NULL;

    token = strtok(str_c, delim.c_str()); 
    while (token != NULL) { 
        tokens.push_back(std::string(token));  
        token = strtok(NULL, delim.c_str()); 
    }

    delete[] str_c;

    return tokens;
}
XLVII
  • 119
  • 9
  • 1
    Since you passed `str` by value, there's no need to call `strdup`. This is also the right use-case for `emplace_back()` rather than `push_back`. – jezza Aug 15 '22 at 10:35
  • `strdup` obtains memory with `malloc`. But you're freeing it with `delete[]`. – Steve Ward Nov 10 '22 at 03:04
0
template<typename C, typename T>
auto insert_in_container(C& c, T&& t) -> decltype(c.push_back(std::forward<T>(t)), void()) {
    c.push_back(std::forward<T>(t));
}
template<typename C, typename T>
auto insert_in_container(C& c, T&& t) -> decltype(c.insert(std::forward<T>(t)), void()) {
    c.insert(std::forward<T>(t));
}
template<typename Container>
Container splitR(const std::string& input, const std::string& delims) {
    Container out;
    size_t delims_len = delims.size();
    auto begIdx = 0u;
    auto endIdx = input.find(delims, begIdx);
    if (endIdx == std::string::npos && input.size() != 0u) {
        insert_in_container(out, input);
    }
    else {
        size_t w = 0;
        while (endIdx != std::string::npos) {
            w = endIdx - begIdx;
            if (w != 0) insert_in_container(out, input.substr(begIdx, w));
            begIdx = endIdx + delims_len;
            endIdx = input.find(delims, begIdx);
        }
        w = input.length() - begIdx;
        if (w != 0) insert_in_container(out, input.substr(begIdx, w));
    }
    return out;
}
Greck
  • 170
  • 1
  • 7
0

i use pointer arithmetic. inner while for string delimeter if you satify with char delim just remove inner while simply. i hope it is correct. if you notice any mistake or improve please leave the comment.

std::vector<std::string> split(std::string s, std::string delim)
{
    char *p = &s[0];
    char *d = &delim[0];
    std::vector<std::string> res = {""};

    do
    {
        bool is_delim = true;
        char *pp = p;
        char *dd = d;
        while (*dd && is_delim == true)
            if (*pp++ != *dd++)
                is_delim = false;

        if (is_delim)
        {
            p = pp - 1;
            res.push_back("");
        }
        else
            *(res.rbegin()) += *p;
    } while (*p++);

    return res;
}
Radem
  • 29
  • 1
  • 6
  • Welcome to Stack Overflow. While this code may solve the question, [including an explanation](https://meta.stackoverflow.com/questions/392712/explaining-entirely-code-based-answers) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please edit your answer to add explanations and give an indication of what limitations and assumptions apply. – Pawara Siriwardhane May 08 '21 at 03:25
0

A simpler solution would be -

You can use strtok to delimit on the basis of multichar delimiter. Remember to use strdup so that the orignal string isn't mutated.

#include <stdio.h>
#include <string.h>
const char* str = "scott>=tiger";
char *token = strtok(strdup(str), ">=");
while (token != NULL)
    {
        printf("%s\n", token);
        token = strtok(NULL, ">=");
    }
markroxor
  • 5,928
  • 2
  • 34
  • 43
  • If you have a string (which OP does) then copying it using its copy constructor will avoid a potentially expensive call to strlen. Surely we can also switch to using nullptr instead of NULL now that C++11 has been around for 11 years? – jezza Aug 15 '22 at 10:30
0

I looked through the answers and haven't seen an iterator based approach that can be fed into a range loop, so I made one.

This uses C++17 string_views so it shouldn't allocate copies of the string.

struct StringSplit
{
    struct Iterator
    {
        size_t tokenStart_ = 0;
        size_t tokenEnd_ = 0;
        std::string str_;
        std::string_view view_;
        std::string delimiter_;
        bool done_ = false;

        Iterator()
        {
            // End iterator.
            done_ = true;
        }

        Iterator(std::string str, std::string delimiter)
            : str_{std::move(str)}, view_{str_}, delimiter_{
                                                     std::move(delimiter)}
        {
            tokenEnd_ = view_.find(delimiter_, tokenStart_);
        }

        std::string_view operator*()
        {
            return view_.substr(tokenStart_, tokenEnd_ - tokenStart_);
        }

        Iterator &operator++()
        {
            if (tokenEnd_ == std::string::npos)
            {
                done_ = true;
                return *this;
            }

            tokenStart_ = tokenEnd_ + delimiter_.size();
            tokenEnd_ = view_.find(delimiter_, tokenStart_);
            return *this;
        }

        bool operator!=(Iterator &other)
        {
            // We only check if both points to the end.
            if (done_ && other.done_)
            {
                return false;
            }

            return true;
        }
    };

    Iterator beginIter_;

    StringSplit(std::string str, std::string delim)
        : beginIter_{std::move(str), std::move(delim)}
    {
    }

    Iterator begin()
    {
        return beginIter_;
    }

    Iterator end()
    {
        return Iterator{};
    }
};

And example usage would be:

int main()
{
    for (auto token : StringSplit{"<>foo<>bar<><>bar<><>baz<><>", "<>"})
    {
        std::cout << "TOKEN: '" << token << "'" << std::endl;
    }
}

Which prints:

TOKEN: ''
TOKEN: 'foo'
TOKEN: 'bar'
TOKEN: ''
TOKEN: 'bar'
TOKEN: ''
TOKEN: 'baz'
TOKEN: ''
TOKEN: ''

It properly handles empty entries at the beginning and end of the string.

Calmarius
  • 18,570
  • 18
  • 110
  • 157
0

Here is an example of splitting a string with another string using Boost String Algorithms library and Boost Range library. The solution is inspired with (modest) suggestion from the the StringAlgo library documentation, see the Split section.

Below is a complete program with the split_with_string function as well as comprehensive test - try it with godbolt:

#include <iostream>
#include <string>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <boost/range/iterator_range.hpp>

std::vector<std::string> split_with_string(std::string_view s, std::string_view search) 
{
    if (search.empty()) return {std::string{s}};

    std::vector<boost::iterator_range<std::string_view::iterator>> found;
    boost::algorithm::ifind_all(found, s, search);
    if (found.empty()) return {};

    std::vector<std::string> parts;
    parts.reserve(found.size() + 2); // a bit more

    std::string_view::iterator part_begin = s.cbegin(), part_end;
    for (auto& split_found : found)
    {
        // do not skip empty extracts
        part_end = split_found.begin();
        parts.emplace_back(part_begin, part_end);
        part_begin = split_found.end();
    }
    if (part_end != s.end())
        parts.emplace_back(part_begin, s.end());

    return parts;
}

#define TEST(expr) std::cout << ((!(expr)) ? "FAIL" : "PASS") << ": " #expr "\t" << std::endl

int main()
{
    auto s0 = split_with_string("adsf-+qwret-+nvfkbdsj", "");
    TEST(s0.size() == 1);
    TEST(s0.front() == "adsf-+qwret-+nvfkbdsj");
    auto s1 = split_with_string("adsf-+qwret-+nvfkbdsj", "-+");
    TEST(s1.size() == 3);
    TEST(s1.front() == "adsf");
    TEST(s1.back() == "nvfkbdsj");
    auto s2 = split_with_string("-+adsf-+qwret-+nvfkbdsj-+", "-+");
    TEST(s2.size() == 5);
    TEST(s2.front() == "");
    TEST(s2.back() == "");
    auto s3 = split_with_string("-+adsf-+qwret-+nvfkbdsj", "-+");
    TEST(s3.size() == 4);
    TEST(s3.front() == "");
    TEST(s3.back() == "nvfkbdsj");
    auto s4 = split_with_string("adsf-+qwret-+nvfkbdsj-+", "-+");
    TEST(s4.size() == 4);
    TEST(s4.front() == "adsf");
    TEST(s4.back() == "");
    auto s5 = split_with_string("dbo.abc", "dbo.");
    TEST(s5.size() == 2);
    TEST(s5.front() == "");
    TEST(s5.back() == "abc");
    auto s6 = split_with_string("dbo.abc", ".");
    TEST(s6.size() == 2);
    TEST(s6.front() == "dbo");
    TEST(s6.back() == "abc");
}

Tests output:

PASS: s0.size() == 1    
PASS: s0.front() == "adsf-+qwret-+nvfkbdsj" 
PASS: s1.size() == 3    
PASS: s1.front() == "adsf"  
PASS: s1.back() == "nvfkbdsj"   
PASS: s2.size() == 5    
PASS: s2.front() == ""  
PASS: s2.back() == ""   
PASS: s3.size() == 4    
PASS: s3.front() == ""  
PASS: s3.back() == "nvfkbdsj"   
PASS: s4.size() == 4    
PASS: s4.front() == "adsf"  
PASS: s4.back() == ""   
PASS: s5.size() == 2    
PASS: s5.front() == ""  
PASS: s5.back() == "abc"    
PASS: s6.size() == 2    
PASS: s6.front() == "dbo"   
PASS: s6.back() == "abc"    
mloskot
  • 37,086
  • 11
  • 109
  • 136
0

Some answers lack a special case. If you have a csv where you want to read equal number of columns, the code fails for cases like this: Row1: a,b,c,d Row2: g,e,, For Row2 only 3 items are read

A special treatment at end of loop adds an empty string:

if (startIndex != str.size())
    result.emplace_back(str.begin() + startIndex, str.end());  
else if (result.size())     // min 1 separator found before. 
    result.emplace_back();

However it will not add a string if there is only 1 column without delim, which is filled in some rows with data and is empty for other rows

0

Yet another.... This one should be easy to add features to over time without changing the function signature since I used "flags" rather than separate bool options.

utils.h

#include <string>
#include <vector>

namespace utils
{
    void ltrim( std::string &s );
    void rtrim( std::string &s );
    void trim(  std::string &s );
    
    enum SplitFlags
    {
        SPLIT_TRIMMED  = 0x01
    ,   SPLIT_NO_EMPTY = 0x02
    };
    std::vector<std::string> split(
        const std::string &s, const char delimiter, const int flags=0 );
}

utils.cpp

#include <sstream>
#include <algorithm>
#include <cctype>
#include <locale>

#include "utils.h"

void utils::ltrim( std::string &s )
{
    s.erase( s.begin(), std::find_if( s.begin(), s.end(),
        []( unsigned char ch ) { return !std::isspace( ch ); } ) );
}

void utils::rtrim( std::string &s )
{
    s.erase( std::find_if( s.rbegin(), s.rend(),
        []( unsigned char ch ) { return !std::isspace( ch ); } ).base(), s.end() );
}

void utils::trim( std::string &s )
{
    rtrim( s );
    ltrim( s );
}
    
std::vector<std::string> utils::split(
    const std::string &s, const char delimiter, const int flags )
{
    const bool trimmed( flags & SPLIT_TRIMMED  )
             , noEmpty( flags & SPLIT_NO_EMPTY )
    ;
    std::vector<std::string> tokens;
    std::stringstream ss( s );
    for( std::string t; getline( ss, t, delimiter ); )
    {
        if( trimmed ) trim( t );
        if( noEmpty && t.empty() ) continue;
        tokens.push_back( t );
    }
    return tokens;
}

Example use:

const auto parts( utils::split( 
    " , a g , b, c, ", ',', utils::SPLIT_TRIMMED | utils::SPLIT_NO_EMPTY ) );
BuvinJ
  • 10,221
  • 5
  • 83
  • 96
-1

As a bonus, here is a code example of a split function and macro that is easy to use and where you can choose the container type :

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

#define split(str, delim, type) (split_fn<type<std::string>>(str, delim))
 
template <typename Container>
Container split_fn(const std::string& str, char delim = ' ') {
    Container cont{};
    std::size_t current, previous = 0;
    current = str.find(delim);
    while (current != std::string::npos) {
        cont.push_back(str.substr(previous, current - previous));
        previous = current + 1;
        current = str.find(delim, previous);
    }
    cont.push_back(str.substr(previous, current - previous));
    
    return cont;
}

int main() {
    
    auto test = std::string{"This is a great test"};
    auto res = split(test, ' ', std::vector);
    
    for(auto &i : res) {
        std::cout << i << ", "; // "this", "is", "a", "great", "test"
    }
    
    
    return 0;
}
Magix
  • 4,989
  • 7
  • 26
  • 50
-1

Since C++11 it can be done like this:

std::vector<std::string> splitString(const std::string& str,
                                     const std::regex& regex)
{
  return {std::sregex_token_iterator{str.begin(), str.end(), regex, -1}, 
          std::sregex_token_iterator() };
} 

// usually we have a predefined set of regular expressions: then
// let's build those only once and re-use them multiple times
static const std::regex regex1(R"some-reg-exp1", std::regex::optimize);
static const std::regex regex2(R"some-reg-exp2", std::regex::optimize);
static const std::regex regex3(R"some-reg-exp3", std::regex::optimize);

string str = "some string to split";
std::vector<std::string> tokens( splitString(str, regex1) ); 

Notes:

luca
  • 7,178
  • 7
  • 41
  • 55
-5
std::vector<std::string> split(const std::string& s, char c) {
  std::vector<std::string> v;
  unsigned int ii = 0;
  unsigned int j = s.find(c);
  while (j < s.length()) {
    v.push_back(s.substr(i, j - i));
    i = ++j;
    j = s.find(c, j);
    if (j >= s.length()) {
      v.push_back(s.substr(i, s,length()));
      break;
    }
  }
  return v;
}
Yilei
  • 239
  • 3
  • 4
  • 3
    Please be more accurate. Your code will not compile. See declaration of "i" and the comma instead of a dot. – jstuardo Mar 30 '17 at 12:28