Литмир - Электронная Библиотека
A
A

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

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

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

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

Очевидно, что наиболее интересной операцией является оператор ввода

>>
. Он также является самым сложным для определения. Наша общая стратегия состоит в том, чтобы считать всю строку из потока
istream
в строку
line
. Затем мы превратим все наши разделители в пробелы (
' '
). После этого отправим строку в поток i
stringstream
с именем
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<line.size(); ++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;

  buffer.clear();

  // заполняем объект buffer

}

Если объект

buffer
находится в состоянии
bad()
или существуют проблемы с источником данных, работа прекращается; в противном случае объект
buffer
очищается и выполняется новая попытка. Мы должны очистить объект
buffer
, потому что попадем в “цикл заполнения”, только если попытка ввода закончится неудачей. Обычно это происходит, если вызывается функция
eof()
для объекта
buffer;
иначе говоря, когда в объекте
buffer
не остается больше символов для чтения. Обработка состояний потока всегда запутанна и часто является причиной очень тонких ошибок, требующих утомительной отладки. К счастью, остаток цикла заполнения вполне очевиден.

string line;

getline(source,line); // вводим строку line из потока source

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

for (int i =0; i<line.size(); ++i)

  if (is_whitespace(line[i]))

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

  else if (!sensitive)

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

  buffer.str(line);             // вводим строку в поток

Считываем строку в объект

buffer
, затем просматриваем каждый символ строки в поисках кандидатов на замену. Функция
is_whitespace()
является членом класса
Punct_stream
, который мы определим позднее. Функция
tolower()
— это стандартная библиотечная функция, выполняющая очевидное задание, например превращает символ
A
в символ
a
(см. раздел 11.6).

После правильной обработки строки

line
ее необходимо записать в поток
istringstream
. Эту задачу выполняет функция
buffer.str(line);
эту команду можно прочитать так: “Поместить строку из объекта
buffer
класса
istringstream
в объект
line
”.

Обратите внимание на то, что мы “забыли” проверить состояние объекта

source
после чтения данных с помощью функции
getline()
. Это не обязательно, поскольку в начале цикла выполняется проверка условия
!source.good()
.

163
{"b":"847443","o":1}