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

  bool is_whitespace(char c); // является ли c набором

                              // разделителей?

  void case_sensitive(bool b) { sensitive = b; }

  bool is_case_sensitive() { return sensitive; }

  Punct_stream& operator>>(string& s);

  operator bool();

private:

  istream& source;      // источник символов

  istringstream buffer; // буфер для форматирования

  string white;         // символы–разделители

  bool sensitive;       // является ли поток чувствительным

                        // к регистру?

};

Как и в предыдущем примере, основная идея — ввести строку из потока istream как одно целое, преобразовать символы-разделители в пробелы, а затем использовать поток istringstream для форматирования. Кроме обработки разделителей, заданных пользователем, в классе Punct_stream есть аналогичная возможность: если вызвать функцию case_sensitive(), то она преобразует ввод, чувствительный к регистру, в нечувствительный.

Например, можно приказать объекту класса Punct_stream прочитать строку

Man bites dog!

как

man

bites

dog

Конструктор класса Punct_stream получает поток istream, используемый как источник символов, и присваивает ему локальное имя source. Кроме того, конструктор по умолчанию делает поток чувствительным к регистру, как обычно. Можно создать объект класса Punct_stream, считывающий данные из потока cin, рассматривающий точку с запятой, двоеточие и точку как разделители, а также переводящий все символы в нижний регистр.

Punct_stream ps(cin);     // объект ps считывает данные из потока cin

ps.whitespace(";:.");     // точка с запятой, двоеточие и точка

                          // также являются разделителями

ps.case_sensitive(false); // нечувствительный к регистру

Очевидно, что наиболее интересной операцией является оператор ввода >>. Он также является самым сложным для определения. Наша общая стратегия состоит в том, чтобы считать всю строку из потока istream в строку line. Затем мы превратим все наши разделители в пробелы (' '). После этого отправим строку в поток istringstream с именем buffer. Теперь для считывания данных из потока buffer можно использовать обычные разделители и оператор >>. Код будет выглядеть немного сложнее, поскольку мы только пытаемся считать данные из потока buffer и заполняем его, только если он пуст.

Punct_stream& Punct_stream::operator>>(string& s)

{

  while (!(buffer>>s)) { // попытка прочитать данные

                         // из потока buffer

  if (buffer.bad() || !source.good()) return *this;

  buffer.clear();

  string line;

  getline(source,line); // считываем строку line

                        // из потока source

                        // при необходимости заменяем символы

  for (int i =0; i

    if (is_whitespace(line[i]))

      line[i]= ' ';               // в пробел

    else if (!sensitive)

      line[i] = tolower(line[i]); // в нижний регистр

    buffer.str(line);             // записываем строку в поток

  }

  return *this;

}

Рассмотрим этот код шаг за шагом. Сначала обратим внимание не нечто необычное.

while (!(buffer>>s)) {

Если в потоке buffer класса istringstream есть символы, то выполняется инструкция buffer>>s и объект s получит слово, разделенное разделителями; больше эта инструкция ничего не делает. Эта инструкция будет выполняться, пока в объекте buffer есть символы для ввода. Однако, когда инструкция buffer>>s не сможет выполнить свою работу, т.е. если выполняется условие !(buffer>>s), мы должны наполнить объект buffer символами из потока source. Обратите внимание на то, что инструкция buffer>>s выполняется в цикле; после попытки заполнить объект buffer мы должны снова попытаться выполнить ввод.

while (!(buffer>>s)) { // попытка прочитать символы из буфера

  if (buffer.bad() || !source.good()) return *this;

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