40

The following trick using istringstream to split a string with white spaces.

int main() {
    string sentence("Cpp is fun");
    istringstream in(sentence);
    vector<string> vec = vector<string>(istream_iterator<string>(in), istream_iterator<string>());
    return 0;
}

Is there a similar trick to split a string with any delimiter? For instance, | in "Cpp|is|fun".

roxrook
  • 13,511
  • 40
  • 107
  • 156
  • 2
    FYI: http://stackoverflow.com/questions/236129/how-to-split-a-string – Ryan Li Dec 26 '10 at 11:30
  • 1
    An (IMO) more relevant answer would be: http://stackoverflow.com/questions/2338827/reading-formatted-data-with-cs-stream-operator-when-data-has-spaces/2343074#2343074. Actually most of these are roughly similar: http://stackoverflow.com/search?q=user%3A179910+imbue – Jerry Coffin Dec 26 '10 at 11:39
  • 9
    should be: "vector vec( istream_iterator( in ), istream_iterator() );" as in your example, you'd be making a instansiation, then invoking the copy-constructor of std::vector. –  Dec 26 '10 at 17:17
  • @Ben Tou CHeh: the one you mentioned is the most vexing parse in C++. You might want to take a look at this thread:http://stackoverflow.com/questions/4511733/cannot-access-vector-when-constructing-with-istream-iterator-range – roxrook Dec 26 '10 at 19:23
  • @Jerry Coffin, Ryan Li: Thanks a lot guys ;) – roxrook Dec 26 '10 at 19:24
  • 9
    @Chan: Adding an extra pair of round brackets for compile-time purposes is a small price to pay when compared to the other options which will incure a run-time penalty each and every time it is called. –  Dec 26 '10 at 19:53
  • In GCC, the only you nead is to add delimeters as second parameter to std::istream_iterator constructor: istream_iterator(in, " ,|") – Sergei Krivonos Aug 20 '15 at 13:31

3 Answers3

20

Generally speaking the istringstream approach is slow/inefficient and requires at least as much memory as the string itself (what happens when you have a very large string?). The C++ String Toolkit Library (StrTk) has the following solution to your problem:

#include <string>
#include <vector>
#include <deque>
#include "strtk.hpp"
int main()
{
   std::string sentence1( "Cpp is fun" );
   std::vector<std::string> vec;
   strtk::parse(sentence1," ",vec);

   std::string sentence2( "Cpp,is|fun" );
   std::deque<std::string> deq;
   strtk::parse(sentence2,"|,",deq);

   return 0;
}

More examples can be found Here

  • 18
    This does not answer the question because the question is about splitting using stream. Difference is in streaming. This could be network stream or stream loading from disk while you parsing. It could be large enough. – Sergei Krivonos Aug 20 '15 at 10:07
15
#include <iostream>
#include <string>
#include <sstream>

int main()
{
  std::istringstream iss { "Cpp|is|fun" };

  std::string s;
  while ( std::getline( iss, s, '|' ) )
    std::cout << s << std::endl;

  return 0;
}

Demo

zdf
  • 4,382
  • 3
  • 18
  • 29
0

The following code uses a regex to find the "|" and split the surrounding elements into an array. It then prints each of those elements, using cout, in a for loop.

This method allows for splitting with regex as an alternative.

#include <iostream>
#include <string>
#include <regex>
#include <algorithm>
#include <iterator>
    
using namespace std;


vector<string> splitter(string in_pattern, string& content){
    vector<string> split_content;

    regex pattern(in_pattern);
    copy( sregex_token_iterator(content.begin(), content.end(), pattern, -1),
    sregex_token_iterator(),back_inserter(split_content));  
    return split_content;
}
    
int main()
{   

    string sentence = "This|is|the|sentence";
    //vector<string> words = splitter(R"(\s+)", sentence); // seperate by space
    vector<string> words = splitter(R"(\|)", sentence);

    for (string word: words){cout << word << endl;}

}   
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Scourge
  • 73
  • 5