Reverse each word in the string. All spaces in the string should be retained This was part of a code challenge.  I use them to help me learn c++/c# along with tutorials and guides.  Basically I was taking a string...


  The quick brown fox jumps over the lazy dog.


...and reversing the words in the string like this.


  ehT kciuq nworb xof spmuj revo eht yzal .god


The following code works and compiles.  However, I feel like this was a verbose way to achieve the objective.


  split


This function was a copy paste from another Stack Overflow page.  I'm not sure if this is idiomatic in c++, but it feels like an overkill.  I just used it because it worked when I tested it on single word strings.


  vector_to_string


I came up with this function because I had forgotten how to do this in c++.  I recall a built in function somewhere in its library.


  reverse_words


This was the provided function for the challenge.  Everything inside of the {} is what I came up with.

Everything in the int main() I came up as well for testing.  Test are provided, but I haven't quite learned how to implement this offline yet.  Following is my code, with the test after that.

#include &lt;string&gt;
#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;

using namespace std;

vector&lt;string&gt; split(string s, string delimiter)
{
    size_t pos_start = 0, pos_end, delim_len = delimiter.length();
    string token;
    vector&lt;string&gt; res;

    while ((pos_end = s.find(delimiter, pos_start)) != 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;
}

string vector_to_string(vector&lt;string&gt; v)
{
    string s;

    for (auto &amp;e : v)
    {
        reverse(e.begin(), e.end());
        s += e + " ";
    }

    return s;
}

string reverse_words(string str)
{
    vector&lt;string&gt; v = split(str, " ");
    string s = vector_to_string(v);
    return s.substr(0, s.length() - 1);
}

int main()
{
    cout &lt;&lt; reverse_words("The quick brown fox jumps over the lazy dog.") &lt;&lt; endl;
    cout &lt;&lt; reverse_words("apple") &lt;&lt; endl;
    cout &lt;&lt; reverse_words("a b c d") &lt;&lt; endl;
    cout &lt;&lt; reverse_words("") &lt;&lt; endl;
    cout &lt;&lt; reverse_words("ab   ba   cd") &lt;&lt; endl;
}


I was provided with these tests:


Describe(Tests)
{
  It(Sample_Test_Cases)
  {
    Assert::That(reverse_words("The quick brown fox jumps over the lazy dog."), Equals("ehT kciuq nworb xof spmuj revo eht yzal .god"));
    Assert::That(reverse_words("apple"), Equals("elppa"));
    Assert::That(reverse_words("a b c d"), Equals("a b c d"));
    Assert::That(reverse_words("double  spaced  words"), Equals("elbuod  decaps  sdrow"));
    Assert::That(reverse_words(""), Equals(""));
    Assert::That(reverse_words("ab   ba   cd"), Equals("ba   ab   dc"));
  }
};



Anyhow, any advice on this is much appreciated and thank you for your help.  Again, I feel like this is a verbose way to solve this problem and I suspect it can be greatly optimized as well.
The split function


vector&lt;string&gt; split(string s, string delimiter)
{
    size_t pos_start = 0, pos_end, delim_len = delimiter.length();
    string token;
    vector&lt;string&gt; res;

    while ((pos_end = s.find(delimiter, pos_start)) != 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;
}



delim_len should be declared as const, because it doesn't change.  Or simply drop it; it is only used in one place.

This function forces all substrings to be first copied into the token variable and then copied into the vector &mdash; that's two copies.  It can be reduced to one copy by using std::move (defined in &lt;utility&gt;) on the argument to push_back, or by simply dropping the token variable.

The function should have std::string_view (defined in &lt;string_view&gt;) parameters instead of std::string parameters for efficiency.

Putting everything together:

auto split(std::string_view s, std::string_view delimiter)
{
    std::vector&lt;std::string&gt; result;

    std::size_t pos_start = 0, pos_end;
    while ((pos_end = s.find(delimiter, pos_start)) != s.npos) {
        res.push_back(s.substr(pos_start, pos_end - pos_start));
        pos_start = pos_end + delimiter.size();
    }

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


vector_to_string


string vector_to_string(vector&lt;string&gt; v)
{
    string s;

    for (auto &amp;e : v)
    {
        reverse(e.begin(), e.end());
        s += e + " ";
    }

    return s;
}



vector_to_string is a non-descriptive name &mdash; reverse_join may be better.  The delimiter should be an argument rather than hard coded.

This function should strip the last space instead of letting its caller do so.  Note that this function performs two operations logically (reverse and join).

Copying the whole vector takes a lot of space; consider copying one string at a time.

And yes, there is a simpler way to do this using std::accumulate (defined in &lt;numeric&gt;):

auto result = std::accumulate(v.begin(), v.end(), std::string{},
                              [](std::string lhs, std::string_view rhs) {
                                  lhs += rhs;
                                  lhs += ' ';
                                  return lhs;
                              });
result.pop_back();


reverse_words


string reverse_words(string str)
{
    vector&lt;string&gt; v = split(str, " ");
    string s = vector_to_string(v);
    return s.substr(0, s.length() - 1);
}



Again, std::string_view parameter.  Even if the stripping happens here, it should be done using pop_back to avoid copying the string and enable named return value optimization.

Simplification

Here's a simplification, using streams to do the split job:

#include &lt;cassert&gt;
#include &lt;iostream&gt;
#include &lt;sstream&gt;
#include &lt;string&gt;
#include &lt;string_view&gt;

std::streamsize read_spaces(std::istream&amp; is)
{
    std::streamsize count = 0;
    while (is.peek() == ' ') {
        is.get();
        ++count;
    }
    return count;
}

// const std::string&amp; because std::istringstream is constructed from a std::string
std::string reverse_words(const std::string&amp; string)
{
    std::istringstream iss{string};
    std::ostringstream oss{};

    for (std::string word; iss &gt;&gt; word;) {
        std::reverse(word.begin(), word.end());
        oss &lt;&lt; word &lt;&lt; std::string(read_spaces(iss), ' ');
    }
    return oss.str();
}

int main()
{
    assert(reverse_words("The quick brown fox jumps over the lazy dog.") == "ehT kciuq nworb xof spmuj revo eht yzal .god");
    assert(reverse_words("apple") == "elppa");
    assert(reverse_words("a b c d") == "a b c d");
    assert(reverse_words("double  spaced  words") == "elbuod  decaps  sdrow");
    assert(reverse_words("") == "");
    assert(reverse_words("ab   ba   cd") == "ba   ab   dc");
}


(live demo)

Miscellaneous


#include &lt;string&gt;
#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;



Sort the #includes in alphabetical order to each navigation.


using namespace std;



Avoid global using namespace std;.  It brings in many common identifiers from the std namespace and causes name clashes.  Although it doesn't matter too much for a small program, get into the habit of explicitly qualifying names with std:: instead.  An alternative is using declarations (using std::string, std::vector;), which only pulls in the specified names.  See Why is using namespace std; considered bad practice? for more information.