Как построить список с разделителями-запятыми из строк без дополнительного разделителя в конце?

Итак, я пытаюсь сделать что-то вроде этого:

ввод:

hi my name is clara

ожидаемый результат:

hi, my, name, is, clara

Моя программа выглядит так:

#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);
}

Но результат выглядит так

hi, my, name, is, clara, ,

Может кто-нибудь помочь мне это исправить?

3 ответа

Это должно исправить это:

#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;
    };
}

Проверьте рабочую демо - версию здесь пожалуйста.


Я использую эту идиому (шаблон?) Во многих языках программирования и во всех видах задач, в которых вам нужно создать вывод с разделителями из списка, например входы. Приведу аннотацию в псевдокоде:

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

В некоторых случаях можно даже опустить firstIteration индикаторная переменная полностью:

empty output
foreach item in list
    if not is_empty(output)
        add delimiter to output
    add item to output

Вы не ведете дела, когда operator>> не может прочитать ни слова после окончания istringstream был достигнут, таким образом оставив ваш wordпеременная пуста. Вы выводите wordперед проверкой, было ли чтение действительно успешным. Вот почему вы получаете пустое слово в конце вывода. Вам нужно будет проверить это условие, например:

#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);
}

Альтернативно:

#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 << ", ";
    } 
}

Однако любой подход все равно оставит вам запятую в конце последнего слова.

Вы могли бы использовать переменную для управления, когда запятая выводится, например:

#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;
    } 
}

Но в этой ситуации было бы проще просто вывести первое слово само по себе, а затем войти в цикл для вывода оставшихся слов с префиксом запятой, например:

#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;
        }
    } 
}

Если вам нравится решение без предложения if каждый раз, когда выполняется цикл while.

#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 = ", ";
    };
}
Другие вопросы по тегам