Строковые потоки
Библиотека iostream
поддерживает операции над строковыми объектами в памяти. Класс ostringstream
вставляет символы в строку, istringstream читает символы из строкового объекта, а stringstream
может использоваться как для чтения, так и для записи. Чтобы работать со строковым потоком, в программу необходимо включить заголовочный файл
#include <sstream>
Например, следующая функция читает весь файл alice_emma в объект buf
класса ostringstream. Размер buf
увеличивается по мере необходимости, чтобы вместить все символы:
#include <string> #include <fstream> #include <sstream> string read_file_into_string() { ifstream ifile( "alice_emma" ); ostringstream buf; char ch; while ( buf && ifile.get( ch )) buf.put( ch ); return buf.str(); |
}
Функция-член str()
возвращает строку – объект класса string, ассоциированный со строковым потоком ostringstream. Этой строкой можно манипулировать так же, как и “обычным” объектом класса string. Например, в следующей программе text почленно инициализируется строкой, ассоциированной с buf:
int main() { string text = read_file_into_string(); // запомнить позиции каждого символа новой строки vector< string::size_type > lines_of_text; string::size_type pos = 0; while ( pos != string::npos ) { pos = text.find( '\n' pos ); lines_of_text.push_back( pos ); } // ... |
}
Объект класса ostringstream
можно использовать для автоматического форматирования составной строки, т.е. строки, составленной из данных разных типов. Так, следующий оператор вывода автоматически преобразует любой арифметический тип в соответствующее строковое представление, поэтому заботиться о выделении нужного количества памяти нет необходимости:
#include <iostream> #include <sstream> int main() { int ival = 1024; int *pival = &ival; double dval = 3.14159; double *pdval = &dval; ostringstream format_message; // преобразование значений в строковое представление format_message << "ival: " << ival << " адрес ival: " << pival << 'n' << "dval: " << dval << " адрес dval: " << pdval << endl; string msg = format_message.str(); cout << " размер строки сообщения: " << msg.size() << " сообщение: " << msg << endl; |
}
Иногда лучше собрать все диагностические сообщения об ошибках, а не выводить их по мере возникновения. Это легко сделать с помощью перегруженного множества функций форматирования:
string format( string msg, int expected, int received ) { ostringstream message; message << msg << " ожидалось: " << expected << " принято: " << received << "\n"; return message.str(); } string format( string msg, vector<int> *values ); |
Приложение может сохранить такие строки для последующего отображения и даже рассортировать их по серьезности. Обобщить эту идею помогают классы Notify
(извещение), Log
(протокол) и Error
(ошибка).
Поток istringstream
читает из объекта класса string, с помощью которого был сконструирован. В частности, он применяется для преобразования строкового представления числа в его арифметическое значение:
#include <iostream> #include <sstream> #include <string> int main() { int ival = 1024; int *pival = &ival; double dval = 3.14159; double *pdval = &dval; // создает строку, в которой значения разделены пробелами ostringstream format_string; format_string << ival << " " << pival << " " << dval << " " << pdval << endl; // извлекает сохраненные значения в коде ASCII // и помещает их в четыре разных объекта istringstream input_istring( format_string.str() ); input_istring >> ival >> pival >> dval >> pdval; |
Упражнение 20.16
В языке Си форматирование выходного сообщения производится с помощью функций семейства printf(). Например, следующий фрагмент
int ival = 1024; double dval = 3.14159; char cval = 'a'; char *sval = "the end"; printf( "ival: %d\tdval% %g\tcval: %c\tsval: %s", |
ival, dval, cval, sval );
печатает:
ival: 1024 dval: 3.14159 cval: a sval: the end
Первым аргументом printf()
является форматная строка. Каждый символ % показывает, что вместо него должно быть подставлено значение аргумента, а следующий за ним символ определяет тип этого аргумента. Вот некоторые из поддерживаемых типов (полное описание см. в [KERNIGHAN88]):
%d целое число %g число с плавающей точкой %c char |
Дополнительные аргументы printf() на позиционной основе сопоставляются со спецификаторами формата, начинающимися со знака %. Все остальные символы в форматной строке рассматриваются как литералы и выводятся буквально.
Основные недостатки семейства функций printf()
таковы: во-первых, форматная строка не обобщается на определенные пользователем типы, и, во-вторых, если типы или число аргументов не соответствуют форматной строке, компилятор не заметит ошибки, а вывод будет отформатирован неверно. Однако у функций printf()
есть и достоинство – компактность записи.
1. Получите так же отформатированный результат с помощью объекта класса ostringstream.
2. Сформулируйте достоинства и недостатки обоих подходов.