8.3.1. Использование класса istringstream
Класс istringstream зачастую используют тогда, когда некую работу следует выполнить со всей строкой и другую работу с отдельными словами в пределах строки.
Предположим, например, что имеется файл, содержащий список людей и номеров их телефонов. У одних людей есть только один номер, а у других несколько — домашний телефон, рабочий, мобильный и т.д. Наш исходный файл может выглядеть следующим образом:
morgan 2015552368 8625550123
drew 9735550130
lee 6095550132 2015550175 8005550000
Каждая запись в этом файле начинается с имени, затем следует один или несколько номеров телефонов. Для начала определим простой класс, представляющий исходные данные:
// по умолчанию члены являются открытыми; см. раздел 1.2
struct PersonInfo {
string name;
vector<string> phones;
};
Один член класса PersonInfo будет представлять имя человека, а вектор будет содержать переменное количество его номеров телефонов.
Наша программа будет читать файл данных и создавать вектор объекта класса PersonInfo. Каждый элемент вектора будет соответствовать одной записи в файле. Ввод обрабатывается в цикле, который читает запись, а затем извлекает имя и номера телефона каждого человека:
string line, word; // будут содержать строку и слово из ввода
vector<PersonInfо> people; // будет содержать все записи из ввода
// читать ввод по строке за раз, пока не встретится конец файла
// (или другая ошибка)
while (getline(cin, line)) {
PersonInfo info; // создать объект для содержания данных записи
istringstream record(line); // связать запись с читаемой строкой
record >> info.name; // читать имя
while (record >> word) // читать номер телефона
info.phones.push_back(word); // и сохранить их
people.push_back(info); // добавить эту запись в people
}
Здесь для чтения всей записи со стандартного устройства ввода используется функция getline(). Если вызов функции getline() успешен, то переменная line будет содержать запись из входного файла. В цикле while определяется локальный объект PersonInfo для содержания данных из текущей записи.
Затем с только что прочитанной строкой связывается поток istringstream. Теперь для чтения каждого элемента в текущей записи можно использовать оператор ввода класса istringstream. Сначала читается имя, затем следует цикл while, читающий номера телефонов данного человека.
Внутренний цикл while завершается, когда все данные в строке прочитаны. Этот цикл работает аналогично другим, написанным для чтения из объекта cin. Различие только в том, что этот цикл читает данные из строки, а не со стандартного устройства ввода. Когда строка прочитана полностью, встретившийся "конец файла" свидетельствует о том, что следующая операция ввода в объект record потерпит неудачу.
Внешний цикл while завершается добавлением в вектор только что обработанного объекта класса PersonInfo. Внешний цикл while продолжается, пока объект cin не встретит конец файла.
Упражнения раздела 8.3.1
Упражнение 8.9. Используйте функцию, написанную для первого упражнения 8.1.2, для вывода содержимого объекта класса istringstream.
Упражнение 8.10. Напишите программу для сохранения каждой строки из файла в векторе vector<string>. Затем используйте объект класса istringstream для чтения каждого элемента из вектора по одному слову за раз.
Упражнение 8.11. Программа этого раздела определила свой объект класса istringstream во внешнем цикле while. Какие изменения необходимо внести, чтобы определить объект record вне этого цикла? Перепишите программу, перенеся определение объекта record во вне цикла while, и убедитесь, все ли необходимые изменения внесены.
Упражнение 8.12. Почему в классе PersonInfo не использованы внутриклассовые инициализаторы?
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОК