, затем просматриваем каждый символ строки в поисках кандидатов на замену. Функция
is_whitespace
является членом класса
Punct_stream
, который мы определим позднее. Функция
tolower
— это стандартная библиотечная функция, выполняющая очевидное задание, например превращает символ
A
в символ
a
(см. раздел 11.6).
После правильной обработки строки
line
ее необходимо записать в поток
istringstream
. Эту задачу выполняет функция
buffer.str(line);
эту команду можно прочитать так: “Поместить строку из объекта
buffer
класса
istringstream
в объект
line
”.
Обратите внимание на то, что мы “забыли” проверить состояние объекта
source
после чтения данных с помощью функции
getline
. Это не обязательно, поскольку в начале цикла выполняется проверка условия
!source.good
.
Как всегда, оператор
>>
возвращает ссылку на поток
*this
(раздел 17.10).
Проверка разделителей проста; мы сравниваем символ с каждым символом из строки, в которой записаны разделители.
bool Punct_stream::is_whitespace(char c)
{
for (int i = 0; i<white.size; ++i)
if (c==white[i]) return true;
return false;
}
Напомним, что поток
istringstream
обрабатывает обычные разделители (например, символы перехода на новую строку или пробел) по-прежнему, поэтому никаких особых действий предпринимать не надо.
Это значит, что нам нужен способ для проверки результата выполнения инструкции
ps>>s
, представленного в виде булевого значения. Результатом инструкции
ps>>s
является объект класса
Punct_stream
, поэтому нам нужен способ неявного преобразования класса
Punct_stream
в тип
bool
. Эту задачу решает функция operator
bool
в классе
Punct_stream
.
Функция-член operator
bool
определяет преобразование класса
Punct_stream
в тип
bool
. В частности, она возвращает значение
true
, если эта операция над классом
Punct_stream
прошла успешно.
Теперь можем написать программу.
int main
// вводит текст и создает упорядоченный список всех слов
// из заданного текста, игнорируя знаки пунктуации и регистры,
// а также удаляя дубликаты из полученного результата
{
Punct_stream ps(cin);
ps.whitespace(";:,.?!\"{}<>/&$@#%^*|~"); // \" в строке
// означает "
ps.case_sensitive(false);
cout << "Пожалуйста,
введите слова \n";
vector<string> vs;
string word;
while (ps>>word) vs.push_back(word); // ввод слов
sort(vs.begin,vs.end); // сортировка в лексикографическом
// порядке
for (int i=0; i<vs.size; ++i) // запись в словарь
if (i==0 || vs[i]!=vs[i–1]) cout << vs[i] << endl;
}
Этот код создает упорядоченный список введенных слов. Инструкция
if (i==0 || vs[i]!=vs[i–1])
удаляет дубликаты. Если в программу ввести слова
There are only two kinds of languages: languages that people complain
about, and languages that people don’t use.
то результат ее работы будет выглядеть следующим образом:
about
and
are
complain
don’t
kind
languages
of
only
people
that
there
two
use
Почему мы получили на выходе
don’t
, а не
dont
? Потому что оставили апостроф за пределами списка разделителей
whitespace
.
Внимание: класс
Punct_stream
во многом похож на класс
istream
, но на самом деле отличается от него. Например, мы не можем проверить его состояние с помощью функции
rdstate
, функция
eof
не определена, и нет оператора
>>
, который вводит целые числа. Важно отметить, что мы не можем передать объект класса
Punct_stream
в качестве аргумента функции, ожидающей поток
istream
. Можно ли определить класс
Punct_istream
, который в точности повторял бы поведение класса
istream
? Можно, но у вас пока нет достаточного опыта программирования, вы еще не освоили основы проектирования и не знаете всех возможностей языка (если впоследствии вы вернетесь к этой задаче, то сможете реализовать буферы потоков на уровне профессионала).
Легко ли читать определение класса
Punct_stream
? Понятны ли вам объяснения? Могли бы вы самостоятельно написать такую программу? Еще несколько дней назад вы были новичком и честно закричали бы: “Нет, нет! Никогда!” или “Нет, нет! Вы что, с ума сошли? Очевидно, что ответ на поставленный вопрос отрицательный”. Цель нашего примера заключается в следующем:
• показать реальную задачу и способ ее решения;
• доказать, что это решение можно найти с помощью вполне доступных средств;