1
\$\begingroup\$

I'm working on a text based rpg game and a couple of commands make use of a target and container pattern. So I wrote this function to split the string up on a given word and put it back together. I'm not sure how efficient it will be in the real world, but I think that it can be improved.

An example of such input and output would be:

splitOnWord("turkey leg from table", "from") -> {"turkey leg", "table"}
typedef std::vector<std::string> StringVector;

StringVector splitOnWord(std::string line, std::string word){
    std::stringstream sstr(line);
    StringVector tmp;
    std::string str;
    int rescnt = 0;

    sstr >> str;
    tmp.push_back(str);
    while(sstr >> str) {
        if(str == word) {
            ++rescnt;
            tmp.push_back(std::string());
        } else {
            tmp[rescnt] += ' ';
            tmp[rescnt] += str;
        }
    }
    return tmp;
}
\$\endgroup\$
2
\$\begingroup\$

I'm not overly fond of the tmp.push_back(std::string());.

I'd rather some of the names were clearer and more readable--for example, I'm not entirely sure what rescnt is supposed to mean.

Under the circumstances, I'd tend to wonder whether we're getting enough good out of the stringstream to justify its existence either. They can be handy, but here we don't seem to be putting the capabilities to a whole lot of use.

std::vector<std::string> split(std::string const &in, std::string const &word) {
    std::vector<std::string> ret;

    int begin = 0;
    int end = 0;

    while (std::string::npos != (end = in.find(word, begin))) {
        ret.push_back(in.substr(begin, end-begin));
        begin = end + word.length()+1;
        while (::isspace(in[begin]))
          ++begin;
    }
    ret.push_back(in.substr(begin));
    return ret;
}
\$\endgroup\$
0
\$\begingroup\$

I would extend this even further to have iterator support and other std::basic_string instantiations. The extension might not be worth it if the project is small and unlikely to change.

template <typename CharT, typename CharTraits, 
          typename Allocator, typename OutputIt>
OutputIt split_on_word(const std::basic_string<CharT, CharTraits, Allocator>& in, 
                       const std::basic_string<CharT, CharTraits, Allocator>& word, 
                       OutputIt out)
{
      ...
}

Supporting other string types might be a good thing for internationalization. Also adding a check if the value type of iterator is the same as string type would be a good boon in debugging template issues or avoiding some bugs.

Nevertheless, the extension will require creating and resizing a vector, or using std::back_inserter. So it really should be weighed if the extension worth the trouble.

\$\endgroup\$
0
\$\begingroup\$

There is an even simpler solution:

https://stackoverflow.com/questions/11719538/how-to-use-stringstream-to-separate-comma-separated-strings

You can define a separator between the different words of a stream, which of course can also be any word you like

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.