Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:
class Punct_stream { // аналогичен потоку istream, но пользователь
// может самостоятельно задавать разделители
public:
Punct_stream(istream& is)
:source(is), sensitive(true) { }
void whitespace(const string& s) // создает строку
// разделителей s
{ white = s; }
void add_white(char c) { white += c; } // добавляет символ
// в набор разделителей
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<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); // вводим строку в поток
Поделиться:
Популярные книги
Золушка по имени Грейс
Фантастика:
фэнтези
8.63
рейтинг книги
Отмороженный 6.0
6. Отмороженный
Фантастика:
боевая фантастика
постапокалипсис
рпг
5.00
рейтинг книги
Заставь меня остановиться 2
2. Заставь меня остановиться
Любовные романы:
современные любовные романы
6.29
рейтинг книги
Бальмануг. (не) Баронесса
1. Мир Десяти
Фантастика:
юмористическое фэнтези
попаданцы
5.00
рейтинг книги
Седьмая жена короля
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Камень. Книга вторая
2. Камень
Фантастика:
фэнтези
8.52
рейтинг книги
Неудержимый. Книга IX
9. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Вперед в прошлое!
1. Вперед в прошлое
Фантастика:
попаданцы
5.00
рейтинг книги
6 Секретов мисс Недотроги
2. Мисс Недотрога
Любовные романы:
любовно-фантастические романы
эро литература
7.34
рейтинг книги
Приручитель женщин-монстров. Том 3
3. Покемоны? Какие покемоны?
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Странник
4. Дворянская кровь
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
На границе империй. Том 7. Часть 4
Вселенная EVE Online
Фантастика:
боевая фантастика
космическая фантастика
5.00
рейтинг книги
В зоне особого внимания
12. Девяностые
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Назад в СССР: 1985 Книга 2
2. Спасти ЧАЭС
Фантастика:
попаданцы
альтернативная история
6.00