Читаем Программирование полностью

Теперь мы считали целую строку. Зачем нам это было нужно? Например, неплохой ответ: “Потому что мы сделали то, чего не может оператор >>”. Часто можно слышать совершенно неудачное объяснение: “Потому что пользователь набрал полную строку”. Если это все, что вы можете сказать, то используйте оператор >>, потому что, если вы ввели строку, то должны как-то ее разобрать на части. Рассмотрим пример.

string first_name;

string second_name;

stringstream ss(name);

ss>>first_name;  // ввод строки Dennis

ss>>second_name; // ввод строки Ritchie

Непосредственный ввод данных в строки first_name и second_name можно было бы выполнить проще. Одна из распространенных причин для считывания полной строки заключается в том, что определение разделителя не всегда является достаточно приемлемым. Иногда переход на новую строку желательно трактовать не как разделитель. Например, в ходе обмена сообщениями в компьютерной игре текст разумнее интерпретировать как предложение, не полагаясь на общепринятую пунктуацию.

идти налево, пока не увидишь картину справа на стене

сними картину со стены и открой дверь позади нее. Возьми сундук

В данном случае мы сначала прочитаем всю строку, а затем извлечем из нее отдельные слова.

string command;

getline(cin,command);             // вводим строку

stringstream ss(command);

vector words;

string s;

while (ss>>s) words.push_back(s); // извлекаем отдельные слова

С другой стороны, если есть выбор, то лучше всего ориентироваться на знаки пунктуации, а не на символ перехода на новую строку. 

<p id="AutBody_Root206"><strong>11.6. Классификация символов</strong></p>

Как правило, мы вводим целые числа, числа с плавающей точкой, слова и так далее, в соответствии с общепринятым форматом. Однако мы можем, а иногда и должны, снизить уровень абстракции и ввести отдельные символы. Для этого необходимо затратить больше усилий, но, считывая отдельные символы, мы получаем полный контроль на тем, что делаем. Рассмотрим задачу распознавания лексем в выражениях из раздела 7.8.2.

Допустим, мы хотим разделить выражение 1+4*x<=y/z*5 на одиннадцать лексем.

1 + 4 * x <= y / z * 5

Для ввода чисел мы могли бы использовать оператор >>, но, пытаясь ввести идентификаторы как строки, должны были бы прочитать фразу x<=y как целую строку (поскольку символы < и = не являются разделителями). Сочетание символов z* мы также должны были бы ввести как целую строку (поскольку символ * также не является разделителем).

Вместо этого можно сделать следующее:

char ch;

while (cin.get(ch)) {

  if (isspace(ch)) { // если символ ch является разделителем,

                     // ничего не делаем (так как разделители

                     // игнорируются)

  }

  if (isdigit(ch)) {

                     // вводим число

  }

  else if (isalpha(ch)) {

                     // вводим идентификатор

  }

  else {

                     // обрабатываем операторы

  }

}

Функция istream::get() считывает отдельный символ в свой аргумент. Разделители при этом не игнорируются. Как и оператор >>, функция get() возвращает ссылку на свой поток istream, так что можно проверить его состояние.

При вводе отдельных символов мы обычно хотим классифицировать их: это символ или цифра? В верхнем регистре или в нижнем? И так далее. Для этого существует набор стандартных библиотечных функций.

 Обратите внимание на то, что категории классификации можно объединять с помощью оператора ИЛИ (||). Например, выражение isalnum(c) означает isalpha(c)||isdigit(c); иначе говоря, “является ли символ c буквой или цифрой?”

Кроме того, в стандартной библиотеке есть две полезные функции для уничтожения различий между символами, набранными в разных регистрах.

Это удобно, когда мы хотим устранить различия между символами, набранными в разных регистрах. Например, если пользователь ввел слова Right, right и rigHT, то, скорее всего, он имел в виду одно и то же (например, слово rigHT чаще всего является результатом нечаянного нажатия клавиши ). Применив функцию tolower() к каждому символу в каждой из строк, мы можем получить одно и то же значение: right. Эту операцию можно выполнить с любым объектом класса string.

void tolower(string& s) // вводит строку s в нижнем регистре

{

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже