1

So i'm trying to do something like this:

input:

hi my name is clara

expected output:

hi, my, name, is, clara

My program looks like this:

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main()
{

    string str;

    getline(cin, str);

    istringstream ss(str);
    do {
        string word;
        ss >> word;
        cout << word << ", ";
    } 
    while (ss);
}

But the output looks like this

hi, my, name, is, clara, ,

Can someone help me fix this?

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
clarawalsh
  • 21
  • 3

3 Answers3

3

This should fix it:

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

using namespace std;

int main() {

    string str;

    getline(cin, str);
    
    string word;
    istringstream ss(str);
    bool firstIteration = true;
    while(ss >> word) {
        if(!firstIteration) {
            cout  << ", ";
        }
        cout << word;
        firstIteration = false;
    };
}

Check the working demo here please.


I am using this idiom (pattern?) in many programming languages, and all kind of tasks where you need to construct delimited output from list like inputs. Let me give the abstract in pseudo code:

empty output
firstIteration = true
foreach item in list
    if firstIteration
        add delimiter to output
    add item to output
    firstIteration = false

In some cases one could even omit the firstIteration indicator variable completely:

empty output
foreach item in list
    if not is_empty(output)
        add delimiter to output
    add item to output
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • 1
    Nice and super easy. – seccpur Sep 08 '20 at 16:18
  • 1
    Here is another simple idiom: `empty output, if read item from list then add item to output, foreach remaining item in list do add delimiter and item to output` No need for `firstIteration` or `is_empty()`, those are just wasteful operations while looping. – Remy Lebeau Sep 08 '20 at 19:01
  • @remy If `is_empty(output)` is a costly operation depends (that's why I said _in some cases_). E.g. thinking of Delphi's `string_var = ''` `string_var.empty()` that's not really costly (as is for all `bstr_t` variants). – πάντα ῥεῖ Sep 08 '20 at 19:19
1

You are not handling the case when operator>> fails to read a word once the end of the istringstream has been reached, thus leaving your word variable empty. You are outputting the word before checking if the read was actually successful. That is why you end up with a blank word at the end of your output. You would need to check for that condition, eg:

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main()
{
    string str;
    getline(cin, str);

    istringstream ss(str);

    do {
        string word;
        if (!(ss >> word)) break;
        cout << word << ", ";
    } 
    while (true);
}

Alternatively:

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main()
{
    string str;
    getline(cin, str);

    istringstream ss(str);
    string word;

    while (ss >> word)
    {
        cout << word << ", ";
    } 
}

However, either approach would still leave you with a trailing comma at the end of the last word.

You could use a variable to control when the comma is output, eg:

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main()
{
    string str;
    getline(cin, str);

    istringstream ss(str);
    string word;
    bool first = true;

    while (ss >> word)
    {
        if (first)
            first = false;
        else
            cout << ", ";

        cout << word;
    } 
}

But, in this situation, it would be cleaner to simply output the first word by itself, and then enter a loop to output the remaining words prefixed by a comma, eg:

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main()
{
    string str;
    getline(cin, str);

    istringstream ss(str);
    string word;

    if (ss >> word)
    {
        cout << word;

        while (ss >> word)
        {
            cout << ", " << word;
        }
    } 
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

If you like a solution without a if-clause each time the while loops executes.

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

using namespace std;

int main() {

    string str;

    getline(cin, str);
    
    string word;
    istringstream ss(str);
    string delimiter = "";
    while(ss >> word) {
        cout << delimiter << word;
        delimiter = ", ";
    };
}
Lucian
  • 3,407
  • 2
  • 21
  • 18