Использование операторов вставки и управление форматом
В этой статье описывается, как управлять форматом и как создавать операторы вставки для собственных классов. Оператор вставки (<<
), который изначально включен во все стандартные типы данных C++, отправляет байты в объект потока вывода. Операторы вставки работают с предопределенными "манипуляторами" — элементами, которые изменяют формат целочисленных аргументов, заданный по умолчанию.
Форматом можно управлять с помощью следующих параметров:
Ширина выходных данных
Чтобы выровнять выходные данные, необходимо указать ширину вывода для каждого элемента, поместив setw
манипулятор в поток или вызвав width
функцию-член. В этом примере выравниваются по правому краю значения в столбце шириной по крайней мере 10 символов:
// output_width.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main( )
{
double values[] = { 1.23, 35.36, 653.7, 4358.24 };
for( int i = 0; i < 4; i++ )
{
cout.width(10);
cout << values[i] << '\n';
}
}
1.23
35.36
653.7
4358.24
Начальные пробелы добавляются в любое значение шириной менее 10 символов.
Чтобы заполнить поле, используйте fill
функцию-член, которая задает значение символа заполнения для полей, имеющих указанную ширину. По умолчанию используется пробел. Чтобы заполнить столбец чисел звездочками, измените предыдущий for
цикл следующим образом:
for (int i = 0; i <4; i++)
{
cout.width(10);
cout.fill('*');
cout << values[i] << endl;
}
Манипулятор endl
заменяет символ перевода строки ('\n'
). Выходные данные выглядят следующим образом.
******1.23
*****35.36
*****653.7
***4358.24
Чтобы указать ширину элементов выходных данных в той же строке, используйте манипулятор setw
:
// setw.cpp
// compile with: /EHsc
#include <iostream>
#include <iomanip>
using namespace std;
int main( )
{
double values[] = { 1.23, 35.36, 653.7, 4358.24 };
const char *names[] = { "Zoot", "Jimmy", "Al", "Stan" };
for( int i = 0; i < 4; i++ )
cout << setw( 7 ) << names[i]
<< setw( 10 ) << values[i] << endl;
}
Функция-член width
объявлена в <iostream>
. Если вы используете setw
или любой другой манипулятор с аргументами, необходимо включить <iomanip>
. В выходных данных строки печатаются в поле ширины 6 и целых чисел в поле ширины 10:
Zoot 1.23
Jimmy 35.36
Al 653.7
Stan 4358.24
setw
и width
не усечение значений. Если форматированные выходные данные превышают ширину, значения выводятся полностью в соответствии с заданной в потоке точностью. width
Оба setw
и влияют только на следующее поле. Для ширины поля восстанавливается значение по умолчанию (необходимая ширина) после вывода одного поля. Другие параметры форматирования потока остаются в силе, пока не будут изменены.
Точное понимание
По умолчанию выравнивание текста в потоках вывода задано по правому краю. Чтобы выровнять имена в предыдущем примере и выровнять их по правому краю, замените for
цикл следующим образом:
for (int i = 0; i <4; i++)
cout << setiosflags(ios::left)
<< setw(6) << names[i]
<< resetiosflags(ios::left)
<< setw(10) << values[i] << endl;
Выходные данные выглядят следующим образом.
Zoot 1.23
Jimmy 35.36
Al 653.7
Stan 4358.24
Флаг выравнивания слева устанавливается с помощью setiosflags
манипулятора left
с перечислителем. Этот перечислитель определен в ios
классе, поэтому его ссылка должна содержать ios::
префикс. Манипулятор resetiosflags
отключает флаг выравнивания слева. В отличие width
от и setw
, эффект setiosflags
и resetiosflags
является постоянным.
Точность
По умолчанию для чисел с плавающей запятой задана точность шесть. Например, число 3466,9768 выводится как 3466,98. Чтобы изменить способ печати этого значения, используйте манипулятор setprecision
. Манипулятор имеет два флага: fixed
и scientific
. Если fixed
задано, число выводится как 3466,976800. Если scientific
задано, он печатается как 3.4669773+003.
Чтобы отобразить числа с плавающей запятой, показанные в выравнивании с одной значительной цифрой, замените for
цикл следующим образом:
for (int i = 0; i <4; i++)
cout << setiosflags(ios::left)
<< setw(6)
<< names[i]
<< resetiosflags(ios::left)
<< setw(10)
<< setprecision(1)
<< values[i]
<< endl;
Программа выведет этот список:
Zoot 1
Jimmy 4e+01
Al 7e+02
Stan 4e+03
Чтобы исключить научное нотацию, вставьте следующую инструкцию перед циклом for
:
cout << setiosflags(ios::fixed);
С фиксированной нотацией программа выводит числа с одной цифрой после десятичной запятой.
Zoot 1.2
Jimmy 35.4
Al 653.7
Stan 4358.2
Если вы измените флагios::scientific
, программа выводит следующееios::fixed
:
Zoot 1.2e+00
Jimmy 3.5e+01
Al 6.5e+02
Stan 4.4e+03
В этом случае программа также выводит числа с одной цифрой после десятичной запятой. ios::fixed
Если задано значение ios::scientific
точности, оно определяет число цифр после десятичной запятой. Если не установлен ни один из флагов, значение точности определяет общее количество значащих цифр. Манипулятор resetiosflags
снимает эти флаги.
Основание системы счисления
Для dec
oct
hex
ввода и вывода манипуляторы задают радикс по умолчанию для входных и выходных данных. Например, при вставке манипулятора hex
в выходной поток объект правильно преобразует внутреннее представление целых чисел в шестнадцатеричный выходной формат. Числа отображаются с цифрами f в нижнем регистре, если uppercase
флаг очищается (по умолчанию); в противном случае они отображаются в верхнем регистре. По умолчанию радикс имеет значение dec
(десятичное).
Строки в кавычках (C++ 14)
При вставке строки в поток можно легко получить ту же строку обратно, вызвав stringstream::str()
функцию-член. Однако если вы хотите использовать оператор извлечения для вставки потока в новую строку в более позднюю точку, может возникнуть непредвиденный результат, так как >>
оператор по умолчанию остановится при обнаружении первого символа пробела.
std::stringstream ss;
std::string inserted = "This is a sentence.";
std::string extracted;
ss << inserted;
ss >> extracted;
std::cout << inserted; // This is a sentence.
std::cout << extracted; // This
Эту проблему можно устранить вручную, но чтобы сделать обход строки более удобным, C++ 14 добавляет манипулятор потока std::quoted
в <iomanip>
. После вставки quoted()
окружает строку разделителем (двойным кавычки " по умолчанию) и при извлечении потока выполняется обработка потока для извлечения всех символов до тех пор, пока конечный разделитель не найден. Все внедренные кавычки экранируются с помощью escape-символа ('\\' по умолчанию).
Разделители присутствуют только в объекте потока; Они не присутствуют в извлеченной строке, но они присутствуют в строке, возвращаемой basic_stringstream::str
.
Обработка пробелов операциями вставки и извлечения не зависит от способа представления строки в коде, поэтому заключение оператора в кавычки будет полезно в любом случае, независимо от того, является входная строка необработанным строковым литералом или обычной строкой. Входная строка, независимо от его формата, может содержать внедренные кавычки, разрывы строк, вкладки и т. д., и все они будут сохранены манипулятором quoted()
.
Дополнительные сведения и полные примеры кода см. в разделе quoted
.