标准格式说明

来自cppreference.com
< cpp‎ | utility‎ | format


 
 
工具库
语言支持
类型支持(基本类型、RTTI)
库功能特性测试宏 (C++20)
动态内存管理
程序工具
协程支持 (C++20)
变参数函数
调试支持
(C++26)
三路比较
(C++20)
(C++20)(C++20)(C++20)
(C++20)(C++20)(C++20)
通用工具
日期和时间
函数对象
格式化库 (C++20)
(C++11)
关系运算符 (C++20 中弃用)
整数比较函数
(C++20)(C++20)(C++20)   
(C++20)
交换类型运算
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
常用词汇类型
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)
初等字符串转换
(C++17)
(C++17)

 
 

对于基本类型和字符串类型,格式说明基于 Python 中的格式说明

格式说明的语法是:

填充与对齐 (可选) 正负号 (可选) #(可选) 0(可选) 宽度 (可选) 精度 (可选) L(可选) 类型 (可选)

正负号#0 选项只有在使用整数或浮点显示类型时合法。

填充与对齐

填充与对齐 是一个可选的填充字符(可以是除 {} 以外的任何字符),后随对齐 选项 <>^ 之一。

如果未指定填充字符,则缺省为空格字符。对于 Unicode 编码的格式说明,填充字符必须对应于单个 Unicode 标量值。

对齐 选项的意义如下:

  • <:强制格式化的实参对齐到可用空间开头,通过在格式化的实参的后面插入 n 个字符。这是使用非整数非浮点显示类型时的默认选项。
  • >:强制格式化的实参对齐到可用空间末尾,通过在格式化的实参的前面插入 n 个字符。这是使用整数或浮点显示类型时的默认选项。
  • ^:强制格式化的实参在可用空间中央,通过在格式化的实参的前面插入
    n
    2
    个字符,后面插入
    n
    2
    个字符。

在所有情况下,n 是最小域宽(以 宽度 指定)和格式化的实参的预计宽度的差,或者在差小于 0 时是 0。

char c = 120;
auto s0 = std::format("{:6}", 42);    // s0 的值是 "    42"
auto s1 = std::format("{:6}", 'x');   // s1 的值是 "x     "
auto s2 = std::format("{:*<6}", 'x'); // s2 的值是 "x*****"
auto s3 = std::format("{:*>6}", 'x'); // s3 的值是 "*****x"
auto s4 = std::format("{:*^6}", 'x'); // s4 的值是 "**x***"
auto s5 = std::format("{:6d}", c);    // s5 的值是 "   120"
auto s6 = std::format("{:6}", true);  // s6 的值是 "true  "

正负号、# 与 0

正负号 选项可以是下列之一:

  • +:指示应该对于非负数和负数都使用正负号。在非负数的输出值前插入 + 号。
  • -:指示应该仅对于负数使用正负号(这是默认行为)。
  • 空格:指示应对非负数使用一个前导空格,而对负数使用负号。

负零被当作负数。

正负号 选项适用于浮点无穷大和 NaN。

double inf = std::numeric_limits<double>::infinity();
double nan = std::numeric_limits<double>::quiet_NaN();
auto s0 = std::format("{0:},{0:+},{0:-},{0: }", 1);   // s0 的值是 "1,+1,1, 1"
auto s1 = std::format("{0:},{0:+},{0:-},{0: }", -1);  // s1 的值是 "-1,-1,-1,-1"
auto s2 = std::format("{0:},{0:+},{0:-},{0: }", inf); // s2 的值是 "inf,+inf,inf, inf"
auto s3 = std::format("{0:},{0:+},{0:-},{0: }", nan); // s3 的值是 "nan,+nan,nan, nan"

# 选项导致将代用形式 用于转换。

  • 对于整数类型,使用二进制、八进制或十六进制显示类型时,代用形式会在有正负号字符(可以是空格)时将前缀(0b00x)插入到输出值中正负号字符之后,否则将前缀插入到输出值之前。
  • 对于浮点类型,代用形式导致转换有限值的结果始终含有小数点字符,即使它后面没有数位。正常情况下,小数点字符只有在它后面有数位时才会在转换结果出现。另外,对于 gG 转换,不会从结果移除尾随的零。

0 选项(在任何正负号或底之后)以前导零填充域到域宽,除了应用到无穷大或 NaN 时。如果 0 字符与对齐 选项一同出现,那么忽略 0 字符。

char c = 120;
auto s1 = std::format("{:+06d}", c);   // s1 的值是 "+00120"
auto s2 = std::format("{:#06x}", 0xa); // s2 的值是 "0x000a"
auto s3 = std::format("{:<06}", -42);  // s3 的值是 "-42   "(因 < 对齐忽略 0)

宽度与精度

宽度 是一个正十进制数或嵌套的替换域({}{n })。它存在的情况下会指定最小域宽。

精度 是点(.)后随非负十进制数或嵌套的替换域。此域指示精度或最大域大小。它只能用于浮点与字符串类型。

  • 对于浮点类型,此域指定格式化精度。
  • 对于字符串类型,它提供要复制到输出的字符串前缀的估计宽度(见下文)的上界。对于以 Unicode 编码的字符串,复制到输出的文本是整个扩展字素集群的,使得估计宽度不大于精度的最长前缀。

如果宽度 或精度 中使用嵌套的替换域,而对应的实参不是整数类型 (C++23 前)标准有符号或无符号整数类型 (C++23 起),为负,或对于宽度 为零,那么就会抛出 std::format_error 类型的异常。

float pi = 3.14f;
auto s1 = std::format("{:10f}", pi);           // s1 = "  3.140000" (宽度 = 10)
auto s2 = std::format("{:{}f}", pi, 10);       // s2 = "  3.140000" (宽度 = 10)
auto s3 = std::format("{:.5f}", pi);           // s3 = "3.14000" (精度 = 5)
auto s4 = std::format("{:.{}f}", pi, 5);       // s4 = "3.14000" (精度 = 5)
auto s5 = std::format("{:10.5f}", pi);         // s5 = "   3.14000"
                                               // (宽度 = 10,精度 = 5)
auto s6 = std::format("{:{}.{}f}", pi, 10, 5); // s6 = "   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 的字符串,实现应该估计字符串的宽度为它的扩展字素集群中首个码位的估计宽度之和。如果 Unicode 码位在下列范围内,那么估计宽度是 2,否则是 1:

  • 任意 Unicode 属性 East_Asian_Width 具有值 Fullwidth (F) 或 Wide (W) 的代码点
  • U+4DC0 – U+4DFF(易经六十四卦像)
  • U+1F300 – U+1F5FF(杂项符号和象形文字)
  • U+1F900 – U+1F9FF(补充符号和象形文字)
auto s1 = std::format("{:.^5s}",   "🐱");      // s1 = ".🐱.."
auto s2 = std::format("{:.5s}",    "🐱🐱🐱");  // s2 = "🐱🐱"
auto s3 = std::format("{:.<5.5s}", "🐱🐱🐱");  // s3 = "🐱🐱."

L(本地环境特定的格式化)

L 选项导致使用本地环境特定的形式。此选项仅对算术类型合法。

  • 对于整数类型,本地环境特定形式会按照上下文的本地环境插入适合的数位组分隔字符。
  • 对于浮点类型,本地环境特定形式会按照上下文的本地环境插入适合的数位组和基数分隔字符。
  • 对于 bool 的文本表示,本地环境特定形式使用如同通过 std::numpunct::truenamestd::numpunct::falsename 获得的字符串。

类型

类型 选项确定应该如何显示数据。

可用的字符串显示类型有:

  • 无、s:复制字符串到输出。
  • ?:复制转义后的字符串(见下文)到输出。
(C++23 起)

可用的 charwchar_tbool 以外的整数类型的整数显示类型有:

  • b:二进制格式。如同通过调用 std::to_chars(first, last, value, 2) 产生输出。底前缀是 0b
  • B:同 b,但底前缀是 0B
  • c:复制字符 static_cast<CharT>(value) 到输出,其中 CharT 是格式字符串的字符类型。如果值不在 CharT 的可表示值的范围中,那么就会抛出 std::format_error
  • 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

可用的 charwchar_t 表示类型有:

  • 无、c:复制字符到输出。
  • bBdoxX:使用值分别为 static_cast<unsigned char>(value)static_cast<std::make_unsigned_t<wchar_t>>(value) 的整数表示类型。
  • ?:复制经转义字符(见下文)到输出。
(C++23 起)

可用的 bool 表示类型有:

  • 无、s:复制文本表示(truefalse 或本地环境特定形式)到输出。
  • bBcdoxX:以值 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 指示指数。
  • fF:如同通过调用 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 为 infnan。对于大写表示类型,分别格式化无穷大和 NaN 为 INFNAN

可用的指针表示类型(也用于 std::nullptr_t)有:

  • 无、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 是下表中的字符之一,那么使用对应的转义序列:
字符 转义序列 注解
横向制表(ASCII 编码中是字节 0x09) \t
换行(ASCII 编码中是字节 0x0a) \n
回车(ASCII 编码中是字节 0x0d) \r
双引号(ASCII 编码中是字节 0x22) \" 只会在输出是用双引号包围的字符串时使用
单引号(ASCII 编码中是字节 0x27) \' 只会在输出是用单引号包围的字符串时使用
反斜杠(ASCII 编码中是字节 0x5c) \\
  • 否则,如果 C 不是空格字符(ASCII 编码中是字节 0x20),并且要么
  • 关联的字符编码是 Unicode 编码,并且
  • C 对应的 Unicode 标量具有的 Unicode 属性 General_CategorySeparator (Z) 或 Other (C) 两个组中的某个值,或者
  • C 没有紧接在非转义字符之后,并且 C 对应的 Unicode 标量具有的 Unicode 属性 Grapheme_Extend=Yes,要么
  • 关联的字符编码不是 Unicode 编码,并且 C 是由实现定义的不可打印字符集合中的字符,
那么转义序列是 \u{十六进制数位转义序列 },其中十六进制数位转义序列 是 C 使用小写十六进制数位的最短十六进制表示。
  • 否则,C 按原样复制。
  • 未指定代码单元序列是移位序列时对输出和后续对字符串的解码造成的影响。
  • 每个其他代码单元(即在非良构代码单元序列中的代码单元)都会替换成 \x{十六进制数位转义序列 },其中十六进制数位转义序列 是代码单元使用小写十六进制数位的最短十六进制表示。

字符串的转义字符串表示会通过以上述方式对字符串中的代码单元序列进行转义来构造,并且用双引号包围结果。

字符的转义表示会通过以上述方式对它进行转义来构造,并且用单引号包围结果。

auto s1 = std::format("[{:?}]", "h\tllo");             // s1 的值:["h\tllo"]
auto s2 = std::format("[{:?}]", "Спасибо, Виктор ♥!"); // s2 的值:
                                                       //     ["Спасибо, Виктор ♥!"]
auto s3 = std::format("[{:?}] [{:?}]", '\'', '"');     // s3 的值:['\'', '"']
 
// 以下样例假定采用了 UTF-8 编码
auto s4 = std::format("[{:?}]", std::string("\0 \n \t \x02 \x1b", 9));
                                                  // s4 的值:
                                                  //     [\u{0} \n \t \u{2} \u{1b}]
auto s5 = std::format("[{:?}]", "\xc3\x28");      // 非法 UTF-8
                                                  // s5 的值:["\x{c3}("]
auto s6 = std::format("[{:?}]", "\u0301");        // s6 的值:["\u{301}"]
auto s7 = std::format("[{:?}]", "\\\u0301");      // s7 的值:["\\\u{301}"]
auto s8 = std::format("[{:?}]", "e\u0301\u0323"); // s8 的值:["ẹ́"]
(C++23 起)

注解

大多数情况下,这个语法与老式的 % 格式化类似,添加了 {} 并用 : 取代 %。例如,'%03.2f' 可被翻译成 '{:03.2f}'

功能特性测试 标准 功能特性
__cpp_lib_format_uchar 202311L (C++20)
(DR)
格式化编码单元为无符号整数

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
LWG 3721 C++20 标准格式说明中不允许指定域宽为零 可以通过替换域指定
P2909R4 C++20 charwchar_t 可能被格式化为范围外的无符号整数值 在这种格式化前将编码单元转换为对应的无符号类型