0

EDIT: This is not a duplicate! The question in the link given is different. I'm not separating by spaces, I'm separating by anything other than characters in a given string. Therefor, the answers in the other thread don't work.

EDIT2: Please note that I'm not given the delimiters to separate by, I need to separate by anything OTHER THAN notOf.

In my program, that means cut up string named word into strings in a vector named words, which consist of and are separated by anything other than notOf. So notOf is sort of the opposite of a delimited in getline.

For example, "&otherwise[taken=(and)-redacted-" should become "otherwise", "taken", "and" and "redacted".

I've tried writing and came up with what you see below, but it doesn't work and is also, I've been told, considerably ugly. Use your judgement whether it is worth fixing or writing anew.

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

using namespace std;

int main()
{
    string notOf = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789$'\"";
    string word = "&otherwise[taken=(and)-redacted-";
    stringstream in(word);
    vector<string> words;
    if (word.find_first_not_of(notOf) == string::npos)
        words.push_back(word);
    else while (word.find_first_not_of(notOf) != string::npos)
    {
        int index = word.find_first_not_of(notOf);
        string tok;
        getline(in, tok, word[index]);
        if (index != 0)
            words.push_back(tok);
        word = word.substr(index);
    }
    for (vector<string>::iterator it = words.begin(); it != words.end(); ++it)
        cout << *it << endl;
    system("pause");
    return 0;
}
sonidow
  • 23
  • 3

2 Answers2

1

You can try this :

vector<string>split(string str,string Separator)
{
    vector<string>answer;
    string temp;
    int len=str.size();
    for(int i=0;i<len;i++)
    {
        bool isSeparator=false;
        for(int j=0;j<Separator.length();j++)
        {
            if(str[i]==Separator[j]) 
              isSeparator=true;
        }
        if(!isSeparator) 
        {
            temp+=str[i];
            continue;
        }
        if(temp!="") 
          answer.push_back(temp);
        temp=""; 
    }
    if(temp!="") 
      answer.push_back(temp);
    return answer;
}

You just need to specify the separators in Separator string. This function will return the separated string. Here separating would take place where one of the Separator found.

Edit :

If you want to partition with respect to notOf (that is other than notOf) , you can do the following :

vector<string>split(string str,string Separator)
{
    vector<string>answer;string temp;
    int len=str.size();
    for(int i=0;i<len;i++)
    {
        bool isSeparator=true;
        for(int j=0;j<Separator.length();j++)
        {
            if(str[i]==Separator[j])
              isSeparator=false;
        }
        if(!isSeparator)
        {
            temp+=str[i];
            continue;
        }
        if(temp!="")
          answer.push_back(temp);
        temp="";
    }
    if(temp!="")
      answer.push_back(temp);
    return answer;
}

int main()
{
    string notOf = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789$'\"";
    string word = "&otherwise[taken=(and)-redacted-";
    vector<string>v=split(word,notOf);
    for(int i=0;i<v.size();i++)
      cout<<v[i]<<"\n";
return 0;
}

Hope that helps :)

Ali Akber
  • 3,670
  • 3
  • 26
  • 40
  • Very much helpful function –  Dec 16 '14 at 18:58
  • 1
    Thanks! One problem in using it though, I'm trying to fit this into my program and I can't figure out how to write the while cycle to accomodate this function. `while (word.find_first_not_of(notOf) != string::npos) { char wordz = word[word.find_first_not_of(notOf); string separator(1,wordz); words = split(word, separator);}` – sonidow Dec 16 '14 at 19:19
  • You don't need any while loop :) just pass the string and separator to the function and it will separate the string. In your example : `vector words = split(word,"&[]=()-, .")` If you find it useful then pls accept the answer :) – Ali Akber Dec 16 '14 at 19:24
  • It is useful, but I didn't figure out how to use it to answer my question yet. See, I don't need to separate by `"&[]=()-, ."`, I need to separate by anything OTHER than `notOf` – sonidow Dec 16 '14 at 19:37
0

I was thinking about the most elegant way of doing this if you were given a range of delimiters or valid characters, and using nothing more than the standard library.

Here are my thoughts:

to split words into a string vector by a sequence of delimiters:

template<class Container>
std::vector<std::string> split_by_delimiters(const std::string& input, const Container& delimiters)
{
    std::vector<std::string> result;

    for (auto current = begin(input) ; current != end(input) ; )
    {
        auto first = find_if(current, end(input), not_in(delimiters));
        if (first == end(input)) break;
        auto last = find_if(first, end(input), is_in(delimiters));
        result.emplace_back(first, last);
        current = last;
    }
    return result;
}

to split the other way, by providing a sequence of valid characters:

template<class Container>
std::vector<std::string> split_by_valid_chars(const std::string& input, const Container& valid_chars)
{
    std::vector<std::string> result;

    for (auto current = begin(input) ; current != end(input) ; )
    {
        auto first = find_if(current, end(input), is_in(valid_chars));
        if (first == end(input)) break;
        auto last = find_if(first, end(input), not_in(valid_chars));
        result.emplace_back(first, last);
        current = last;
    }
    return result;
}

is_in and not_in are defined thus:

namespace detail {
    template<class Container>
    struct is_in {
        is_in(const Container& charset)
        : _charset(charset)
        {}

        bool operator()(char c) const
        {
            return find(begin(_charset), end(_charset), c) != end(_charset);
        }

        const Container& _charset;
    };

    template<class Container>
    struct not_in {
        not_in(const Container& charset)
        : _charset(charset)
        {}

        bool operator()(char c) const
        {
            return find(begin(_charset), end(_charset), c) == end(_charset);
        }

        const Container& _charset;
    };

}

template<class Container>
detail::not_in<Container> not_in(const Container& c)
{
    return detail::not_in<Container>(c);
}

template<class Container>
detail::is_in<Container> is_in(const Container& c)
{
    return detail::is_in<Container>(c);
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142