Namespaces
Variants

Standard format specification (since C++20)

From cppreference.net

Для базовых типов и строковых типов спецификация формата основана на спецификации формата в Python .

Синтаксис спецификаций формата:

fill-and-align  (необязательно) sign  (необязательно) # (необязательно) 0 (необязательно) width  (необязательно) precision  (необязательно) L (необязательно) type  (необязательно)

Опции sign , # и 0 действительны только при использовании целочисленного или вещественного типа представления.

Содержание

Заполнение и выравнивание

fill-and-align — это необязательный fill символ (который может быть любым символом, кроме { или } ), за которым следует одна из опций align < , > , ^ .

Если символ заполнения не указан, по умолчанию используется пробел. Для спецификации формата в кодировке Unicode символ заполнения должен соответствовать одному скалярному значению Unicode.

Значение параметров align следующее:

  • < : Принудительно выравнивает форматируемый аргумент по началу доступного пространства, вставляя n символов заполнения после форматируемого аргумента. Это поведение по умолчанию при использовании нецелочисленного невещественного типа представления.
  • > : Принудительно выравнивает форматируемый аргумент по концу доступного пространства, вставляя n символов заполнения перед форматируемым аргументом. Это поведение по умолчанию при использовании целочисленного или вещественного типа представления.
  • ^ : Принудительно центрирует форматируемый аргумент в пределах доступного пространства, вставляя
    n
    2
    символов перед и
    n
    2
    символов после форматируемого аргумента.

В каждом случае, n представляет собой разницу между минимальной шириной поля (заданной параметром width ) и расчетной шириной форматированного аргумента, или 0, если разница меньше 0.

#include <cassert>
#include <format>
int main()
{
    char c = 120;
    assert(std::format("{:6}", 42)    == "    42");
    assert(std::format("{:6}", 'x')   == "x     ");
    assert(std::format("{:*<6}", 'x') == "x*****");
    assert(std::format("{:*>6}", 'x') == "*****x");
    assert(std::format("{:*^6}", 'x') == "**x***");
    assert(std::format("{:6d}", c)    == "   120");
    assert(std::format("{:6}", true)  == "true  ");
}

Знак, # и 0

Опция sign может быть одним из следующих:

  • + : Указывает, что знак должен использоваться как для неотрицательных, так и для отрицательных чисел. Знак + вставляется перед выводом значения для неотрицательных чисел.
  • - : Указывает, что знак должен использоваться только для отрицательных чисел (это поведение по умолчанию).
  • пробел: Указывает, что для неотрицательных чисел должен использоваться ведущий пробел, а для отрицательных - знак минус.

Отрицательный ноль трактуется как отрицательное число.

Опция sign применяется к бесконечности и NaN с плавающей точкой.

#include <cassert>
#include <format>
#include <limits>
int main()
{
    double inf = std::numeric_limits<double>::infinity();
    double nan = std::numeric_limits<double>::quiet_NaN();
    assert(std::format("{0:},{0:+},{0:-},{0: }", 1)   == "1,+1,1, 1");
    assert(std::format("{0:},{0:+},{0:-},{0: }", -1)  == "-1,-1,-1,-1");
    assert(std::format("{0:},{0:+},{0:-},{0: }", inf) == "inf,+inf,inf, inf");
    assert(std::format("{0:},{0:+},{0:-},{0: }", nan) == "nan,+nan,nan, nan");
}

Опция # приводит к использованию альтернативной формы для преобразования.

  • Для целочисленных типов, при использовании двоичного, восьмеричного или шестнадцатеричного формата представления, альтернативная форма вставляет префикс ( 0b , 0 , или 0x ) в выводимое значение после знака (возможно, пробела), если он присутствует, или добавляет его перед выводимым значением в противном случае.
  • Для типов с плавающей точкой, альтернативная форма приводит к тому, что результат преобразования конечных значений всегда содержит символ десятичной точки, даже если за ним не следует цифр. Обычно символ десятичной точки появляется в результате этих преобразований только если после него следует цифра. Кроме того, для преобразований g и G , завершающие нули не удаляются из результата.

Опция 0 заполняет поле ведущими нулями (после любого указания знака или основания) до ширины поля, за исключением случаев применения к бесконечности или NaN. Если символ 0 и опция align присутствуют одновременно, символ 0 игнорируется.

#include <cassert>
#include <format>
int main()
{
    char c = 120;
    assert(std::format("{:+06d}", c)   == "+00120");
    assert(std::format("{:#06x}", 0xa) == "0x000a");
    assert(std::format("{:<06}", -42)  == "-42   "); // 0 игнорируется из-за '<'
}

Ширина и точность

width представляет собой либо положительное десятичное число, либо вложенное поле замены ( {} или { n } ). Если присутствует, задает минимальную ширину поля.

precision — это точка ( . ), за которой следует либо неотрицательное десятичное число, либо вложенное поле замены. Это поле указывает на точность или максимальный размер поля. Оно может использоваться только с типами с плавающей точкой и строковыми типами.

  • Для типов с плавающей запятой это поле определяет точность форматирования.
  • Для строковых типов оно задает верхнюю границу для предполагаемой ширины (см. ниже ) префикса строки, который будет скопирован в вывод. Для строк в Unicode-кодировке текст, копируемый в вывод, представляет собой самый длинный префикс из целых расширенных кластеров графем, предполагаемая ширина которого не превышает точность.

Если для width или precision используется вложенное поле замены, и соответствующий аргумент не является integral type (until C++23) standard signed or unsigned integer type (since C++23) , или является отрицательным, выбрасывается исключение типа std::format_error .

float pi = 3.14f;
assert(std::format("{:10f}", pi)           == "  3.140000"); // ширина = 10
assert(std::format("{:{}f}", pi, 10)       == "  3.140000"); // ширина = 10
assert(std::format("{:.5f}", pi)           == "3.14000");    // точность = 5
assert(std::format("{:.{}f}", pi, 5)       == "3.14000");    // точность = 5
assert(std::format("{:10.5f}", pi)         == "   3.14000"); // ширина = 10, точность = 5
assert(std::format("{:{}.{}f}", pi, 10, 5) == "   3.14000"); // ширина = 10, точность = 5
auto b1 = std::format("{:{}f}", pi, 10.0); // выбрасывает исключение: ширина не целочисленного типа
auto b2 = std::format("{:{}f}", pi, -10);  // выбрасывает исключение: ширина отрицательная
auto b3 = std::format("{:.{}f}", pi, 5.0); // выбрасывает исключение: точность не целочисленного типа

Ширина строки определяется как предполагаемое количество позиций столбцов, подходящих для её отображения в терминале.

Для целей вычисления ширины предполагается, что строка находится в определяемой реализацией кодировке. Метод вычисления ширины не специфицирован, но для строки в Unicode-кодировке реализация должна оценивать ширину строки как сумму оценочных ширин первых кодовых точек в её расширенных кластерах графем . Оценочная ширина равна 2 для следующих кодовых точек, и равна 1 в остальных случаях:

  • Любой кодовый символ, чьё свойство Юникода East_Asian_Width имеет значение Fullwidth ( F ) или Wide ( W )
  • U+4DC0 - U+4DFF (Символы гексаграмм И-Цзин)
  • U+1F300 – U+1F5FF (Разнообразные символы и пиктограммы)
  • U+1F900 – U+1F9FF (Дополнительные символы и пиктограммы)
#include <cassert>
#include <format>
int main()
{
    assert(std::format("{:.^5s}",   "🐱")    == ".🐱..");
    assert(std::format("{:.5s}",    "🐱🐱🐱") == "🐱🐱");
    assert(std::format("{:.<5.5s}", "🐱🐱🐱") == "🐱🐱.");
}

L (форматирование с учетом локали)

Опция L приводит к использованию локализованной формы. Эта опция действительна только для арифметических типов.

  • Для целочисленных типов локализованная форма вставляет соответствующие символы разделителей групп цифр в соответствии с локалью контекста.
  • Для типов с плавающей точкой локализованная форма вставляет соответствующие символы разделителей групп цифр и десятичных разделителей в соответствии с локалью контекста.
  • Для текстового представления bool , локализованная форма использует соответствующую строку, как если бы она была получена с помощью std::numpunct::truename или std::numpunct::falsename .

Тип

Опция type определяет, как данные должны быть представлены.

Доступные типы представления строки:

  • none, s : Копирует строку в вывод.
  • ? : Копирует экранированную строку (см. ниже ) в вывод.
(since C++23)

Доступные целочисленные форматы представления для целочисленных типов, кроме char , wchar_t и bool :

  • b : Двоичный формат. Выводит результат так, как если бы вызывался std:: to_chars ( first, last, value, 2 ) . Префикс системы счисления: 0b .
  • B : аналогично b , но префикс системы счисления: 0B .
  • c : Копирует символ static_cast < CharT > ( value ) в вывод, где CharT — символьный тип строки формата. Выбрасывает std::format_error , если значение не входит в диапазон представимых значений для CharT .
  • d : Десятичный формат. Выводит результат так, как если бы вызывался std:: to_chars ( first, last, value ) .
  • o : Восьмеричный формат. Выводит результат так, как если бы вызывался std:: to_chars ( first, last, value, 8 ) . Префикс системы счисления: 0 , если соответствующее значение аргумента не равно нулю, и пустая строка в противном случае.
  • x : Шестнадцатеричный формат. Выводит результат так, как если бы вызывался std:: to_chars ( first, last, value, 16 ) . Префикс системы счисления: 0x .
  • X : аналогично x , но использует заглавные буквы для цифр выше 9 и префикс системы счисления: 0X .
  • отсутствует: аналогично d .

Доступные char и wchar_t типы представления:

  • none, c : Копирует символ в вывод.
  • b , B , d , o , x , X : Использует целочисленные типы представления со значением static_cast < unsigned char > ( value ) или static_cast < std:: make_unsigned_t < wchar_t >> ( value ) соответственно.
  • ? : Копирует экранированный символ (см. ниже ) в вывод.
(начиная с C++23)

Доступные bool типы представления:

  • none, s : Копирует текстовое представление ( true или false , или локализованную форму) в вывод.
  • b , B , d , o , x , X : Использует целочисленные типы представления со значением static_cast < unsigned char > ( value ) .

Доступные типы представления чисел с плавающей точкой:

  • a : Если указана точность , формирует вывод как при вызове std:: to_chars ( first, last, value, std :: chars_format :: hex , precision ) , где precision — указанная точность; иначе вывод формируется как при вызове std:: to_chars ( first, last, value, std :: chars_format :: hex ) .
  • A : аналогично a , но использует заглавные буквы для цифр выше 9 и P для обозначения экспоненты.
  • e : Формирует вывод как при вызове std:: to_chars ( first, last, value, std :: chars_format :: scientific , precision ) , где precision — указанная точность, или 6, если точность не указана.
  • E : аналогично e , но использует E для обозначения экспоненты.
  • f , F : Формируют вывод как при вызове std:: to_chars ( first, last, value, std :: chars_format :: fixed , precision ) , где precision — указанная точность, или 6, если точность не указана.
  • g : Формирует вывод как при вызове std:: to_chars ( first, last, value, std :: chars_format :: general , precision ) , где precision — указанная точность, или 6, если точность не указана.
  • G : аналогично g , но использует E для обозначения экспоненты.
  • отсутствует: Если указана точность , формирует вывод как при вызове std:: to_chars ( first, last, value, std :: chars_format :: general , precision ) , где precision — указанная точность; иначе вывод формируется как при вызове std:: to_chars ( first, last, value ) .

Для строчных типов представления бесконечность и NaN форматируются как inf и nan соответственно. Для прописных типов представления бесконечность и NaN форматируются как INF и NAN соответственно.

std::format спецификатор std::chars_format соответствующий std::printf спецификатор
a , A std::chars_format::hex a , A (но std::format не выводит ведущие 0x или 0X )
e , E std::chars_format::scientific e , E
f , F std::chars_format::fixed f , F
g , G std::chars_format::general g , G
отсутствует std::chars_format::general если указана точность, иначе кратчайший формат с сохранением точности g если указана точность. Иначе нет соответствующего спецификатора.

Доступные типы представления указателей (также используются для std::nullptr_t ):

  • none, p : Если std::uintptr_t определён, формирует вывод как при вызове std:: to_chars ( first, last, reinterpret_cast < std:: uintptr_t > ( value ) , 16 ) с добавлением префикса 0x к выводу; в противном случае вывод определяется реализацией.
  • P : аналогично p , за исключением того, что использует заглавные буквы для цифр выше 9 и префикс основания 0X .
(начиная с C++26)


Форматирование экранированных символов и строк

Символ или строка могут быть отформатированы как экранированные , чтобы сделать их более подходящими для отладки или логирования.

Экранирование выполняется следующим образом:

  • Для каждой корректной последовательности кодовых единиц, кодирующей символ C :
  • Если C является одним из символов в следующей таблице, используется соответствующая escape-последовательность.
Символ Escape-последовательность Примечания
горизонтальная табуляция (байт 0x09 в кодировке ASCII) \t
перевод строки - новая строка (байт 0x0a в кодировке ASCII) \n
возврат каретки (байт 0x0d в кодировке ASCII) \r
двойная кавычка (байт 0x22 в кодировке ASCII) \" Используется только если вывод представляет собой строку в двойных кавычках
одинарная кавычка (байт 0x27 в кодировке ASCII) \' Используется только если вывод представляет собой строку в одинарных кавычках
обратная косая черта (байт 0x5c в кодировке ASCII) \\
  • В противном случае, если C не является символом пробела (байт 0x20 в кодировке ASCII), и либо
  • связанная кодировка символов является Unicode-кодировкой и
  • C соответствует скалярному значению Unicode, чье свойство Unicode General_Category имеет значение в группах Separator ( Z ) или Other ( C ), или
  • C не предшествует непосредственно неэкранированный символ, и C соответствует скалярному значению Unicode, которое имеет свойство Unicode Grapheme_Extend=Yes , или
  • связанная кодировка символов не является Unicode-кодировкой и C является одним из определенных реализацией разделителей или непечатаемых символов
escape-последовательность имеет вид \u{ hex-digit-sequence } , где hex-digit-sequence - это кратчайшее шестнадцатеричное представление C с использованием строчных шестнадцатеричных цифр.
  • В противном случае, C копируется как есть.
  • Последовательность кодовых единиц, являющаяся сдвиговой последовательностью, имеет неопределенный эффект на вывод и дальнейшее декодирование строки.
  • Другие кодовые единицы (т.е. те, что находятся в некорректных последовательностях кодовых единиц) заменяются на \x{ hex-digit-sequence } , где hex-digit-sequence - это кратчайшее шестнадцатеричное представление кодовой единицы с использованием строчных шестнадцатеричных цифр.

Экранированное строковое представление строки конструируется путем экранирования последовательностей кодовых единиц в строке, как описано выше, и заключения результата в двойные кавычки.

Экранированное представление символа конструируется путем его экранирования, как описано выше, и заключения результата в одинарные кавычки.

Демонстрация в Compiler Explorer :

#include <print>
int main()
{
    std::println("[{:?}]", "h\tllo");             // prints: ["h\tllo"]
    std::println("[{:?}]", "Спасибо, Виктор ♥!"); // prints: ["Спасибо, Виктор ♥!"]
    std::println("[{:?}] [{:?}]", '\'', '"');     // prints: ['\'', '"']
    // The following examples assume use of the UTF-8 encoding
    std::println("[{:?}]", std::string("\0 \n \t \x02 \x1b", 9));
                                             // prints: ["\u{0} \n \t \u{2} \u{1b}"]
    std::println("[{:?}]", "\xc3\x28");      // invalid UTF-8
                                             // prints: ["\x{c3}("]
    std::println("[{:?}]", "\u0301");        // prints: ["\u{301}"]
    std::println("[{:?}]", "\\\u0301");      // prints: ["\\\u{301}"]
    std::println("[{:?}]", "e\u0301\u0323"); // prints: ["ẹ́"]
}
(начиная с C++23)

Примечания

В большинстве случаев синтаксис похож на старый % -форматирование, с добавлением {} и с использованием : вместо % . Например, "%03.2f" может быть преобразован в "{:03.2f}" .

Макрос тестирования возможностей Значение Стандарт Функция
__cpp_lib_format_uchar 202311L (C++20)
(DR)
Форматирование кодовых единиц как беззнаковых целых чисел

Отчеты о дефектах

Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применяется к Поведение в опубликованной версии Корректное поведение
LWG 3721 C++20 ноль не разрешён для поля ширины
в стандартной спецификации формата
ноль разрешён, если указан
через поле замены
P2909R4 C++20 char или wchar_t могут форматироваться как
беззнаковые целые значения вне диапазона
кодовые единицы преобразуются в соответствующий
беззнаковый тип перед таким форматированием