Чтение последовательности слов для добавления их в вектор

Недавно я купил C++ Primer и застрял с проблема. Мне нужно прочитать последовательность слов, используя cin, и сохранить значения в vector. После необычных проблем я обнаружил, что while(cin >> words) вызывает проблемы (например, бесконечный цикл), если вы ожидаете недопустимых входных данных: Использование cin для ввода данных пользователем

int main()
{
    string words;
    vector<string> v;
    cout << "Enter words" << endl;
    while (cin >> words)
    {
        v.push_back(words);
    }
    for(auto b : v)
        cout << b << "  ";
    cout << endl;
    return 0;
}

Поэтому пытаюсь найти альтернативу этой проблеме. Помощь ?


person chosentorture    schedule 15.01.2013    source источник
comment
Если вам не нравится цикл while, когда вы ожидаете, что он закончится?   -  person chris    schedule 16.01.2013
comment
Возможно, вы могли бы поместить условие внутри цикла while на break вне цикла, если условие выполняется.   -  person SShaheen    schedule 16.01.2013
comment
Если вы не ожидаете неверных данных, вы слишком оптимистичны.   -  person jrok    schedule 16.01.2013
comment
Предполагается, что цикл while завершается, когда он сталкивается с недопустимым вводом, но это основная проблема. Если мы подаём неверный ввод в while(std::cin >> words), цикл становится бесконечным.   -  person chosentorture    schedule 16.01.2013
comment
Нет, это не так. Он перестает зацикливаться. Если это конкретное условие дает вам бесконечный цикл, вы делаете что-то еще неправильно.   -  person jrok    schedule 16.01.2013
comment
@jrok я разместил код   -  person chosentorture    schedule 16.01.2013
comment
@Caribou Я разместил код   -  person chosentorture    schedule 16.01.2013
comment
@AyushAgarwal, с минимальными дополнениями для запуска все работает нормально: liveworkspace.org/code/kzsl0%241 . Что считается недействительным?   -  person chris    schedule 16.01.2013
comment
Вы всегда можете проверить строку в теле цикла, посмотреть, действительна ли она (для вашего определения валидности), а затем break вручную, если это необходимо.   -  person jrok    schedule 16.01.2013
comment
@chris Если у нас есть while(std::value), где значение является целым числом, то входные данные любого другого типа должны быть недействительными. Точно так же любые входные данные, кроме строк, должны быть недействительными, но входные данные также принимают целые числа и продолжают работать в коде, который я разместил.   -  person chosentorture    schedule 16.01.2013
comment
«Целое число», введенное пользователем, представляет собой строку. Если вы хотите определить, что является словом, а что нет, вам нужно проверить символы в каждой введенной строке и решить, следует ли помещать их в свой вектор.   -  person paddy    schedule 16.01.2013
comment
@paddy Я пытался решить этот вопрос, и я не уверен, что в этом случае будет «неверный ввод». Авторы C++ Primer постоянно говорили мне, что LOPP while(std << word) остановится, как только вы введете неверный ввод. Я пробовал писать while(getline(cin,words)) но это также приводит к бесконечному циклу.   -  person chosentorture    schedule 16.01.2013
comment
Ага, понятно. Ну, когда дело доходит до строк, на самом деле недопустимых входных данных не бывает. Что они, вероятно, имеют в виду, так это то, что поток заканчивается (например, конец файла или какая-то другая ошибка), но поскольку вы вводите из cin, конца файла нет (в Linux вы можете заставить cin завершиться, нажав Ctrl -Д).   -  person paddy    schedule 16.01.2013
comment
@paddy Так что ты предлагаешь? Я хочу ввести такие слова, как «abc», «свобода», «эффект» и добавить их в вектор. И да, после ввода каждого слова я нажимаю «Ввод», чтобы продолжить ввод следующего слова. Кстати, я использую NetBeans + GCC 4.7.2, если это поможет   -  person chosentorture    schedule 16.01.2013
comment
Затем вы можете потребовать, чтобы пользователь просто нажал клавишу ввода (то есть пустую строку), чтобы закончить добавление слов. Затем вы можете использовать подход getline и остановить цикл, когда пользователь дает вам пустую строку. Поток по-прежнему будет действительным, поэтому вам нужно проверить строку нулевой длины, а затем выйти из цикла. Я добавил код в свой ответ.   -  person paddy    schedule 16.01.2013
comment
@paddy Я только что добавил if(words==" ") после условия while, и теперь, если пользователь вводит пробел, цикл завершается. Хотя я должен был бы уведомить пользователя об этом. Спасибо за этот код! :)   -  person chosentorture    schedule 16.01.2013
comment
@AyushAgarwal Это действительно работает? Если вы читаете с использованием cin >> words, то он никогда не должен давать вам строку, содержащую пробел, если вы явно не изменили входные разделители в потоке.   -  person paddy    schedule 16.01.2013
comment
@paddy Нет, я добавил while(getline(cin, words)) вместо while(cin >> words). После этого я написал if(words==" ") и упомянул, что если пользователь введет пустую строку, то это будет считаться ложным вводом. Но после прочтения кода, который вы предоставили, я переключился на него и использовал if(words.size()==0), и это хорошо работает, если пользователь вводит новую строку во вводе, нажимая «Enter».   -  person chosentorture    schedule 16.01.2013


Ответы (1)


Та ссылка, которую вы предоставили относительно проблем с вводом, немного отличается. Речь идет о том, когда вы ожидаете, что пользователь введет определенное значение, но вы можете не прочитать значение (скажем, целое число), потому что было введено что-то еще. В этом случае хорошо использовать getline, чтобы получить всю строку ввода, а затем проанализировать значение.

В вашем случае вам просто нужны слова. Когда вы читаете строку из потока, она даст вам все последовательные символы, отличные от пробелов. И, игнорируя пунктуацию на мгновение, вы можете назвать это «словом». Поэтому, когда вы говорите о «недопустимом вводе», я не понимаю, что вы имеете в виду. Цикл будет продолжать давать вам «слова» до тех пор, пока в потоке не останется ни одного слова, после чего произойдет ошибка:

vector<string> words;
string word;
while( cin >> word ) words.push_back(word);

Однако, если вы ожидаете, что пользователь введет все слова в одну строку и нажмет Enter, чтобы закончить, вам нужно использовать getline:

// Get all words on one line
cout << "Enter words: " << flush;
string allwords;
getline( cin, allwords );

// Parse words into a vector
vector<string> words;
string word;
istringstream iss(allwords);
while( iss >> word ) words.push_back(word);

Или вы можете сделать это:

cout << "Enter words, one per line (leave an empty line when done)\n";

vector<string> words;
string line;
while( getline(cin, line) )
{
    // Because of the word check that follows, you don't really need this...
    if( line.size() == 0 ) break;

    // Make sure it's actually a word.
    istringstream iss(line);
    string word;
    if( !(iss >> word) ) break;

    // If you want, you can check the characters and complain about non-alphabet
    // characters here...  But that's up to you.

    // Add word to vector
    words.push_back(word);
}
person paddy    schedule 15.01.2013