标准格式规范
对于基本类型和字符串类型,格式规范基于 Python 中的格式规范。
格式规范的语法为
填充和对齐 (可选) 符号 (可选) # (可选) 0 (可选) 宽度 (可选) 精度 (可选) L (可选) 类型 (可选) |
|||||||||
当使用整数或浮点数表示类型时,符号、#
和 0
选项才有效。
内容 |
[编辑] 填充和对齐
填充和对齐 是一个可选的填充 字符(可以是除 {
或 }
之外的任何字符),后跟一个对齐 选项 <
、>
、^
。
如果未指定填充字符,则默认为空格字符。对于 Unicode 编码中的格式规范,填充字符必须对应于单个 Unicode 标量值。
对齐 选项的含义如下
-
<
: 强制格式化后的参数通过在格式化后的参数后插入 n 个填充字符来对齐到可用空间的开头。当使用非整数非浮点数表示类型时,这是默认值。 -
>
: 强制格式化后的参数通过在格式化后的参数前插入 n 个填充字符来对齐到可用空间的结尾。当使用整数或浮点数表示类型时,这是默认值。 -
^
: 强制格式化后的参数通过在格式化后的参数前插入 ⌊
⌋ 个字符,并在格式化后的参数后插入 ⌈n 2
⌉ 个字符来居中对齐到可用空间。n 2
在每种情况下,n 是最小字段宽度(由 宽度 指定)和格式化后的参数的 估计宽度 之间的差值,如果差值小于 0,则为 0。
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
符号 选项可以是以下之一
-
+
: 表示对非负数和负数都应使用符号。对于非负数,+
符号插入到输出值的前面。 -
-
: 表示仅对负数应使用符号(这是默认行为)。 - 空格: 表示对非负数应使用前导空格,对负数应使用减号。
负零被视为负数。
符号 选项适用于浮点数无穷大和小数。
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
选项会用前导零(在任何符号或基数指示符之后)填充字段,直到达到字段宽度,除非它应用于无穷大或小数。如果 0
字符和对齐 选项都出现,则忽略 0
字符。
char c = 120; assert(std::format("{:+06d}", c) == "+00120"); assert(std::format("{:#06x}", 0xa) == "0x000a"); assert(std::format("{:<06}", -42) == "-42 "); // 0 is ignored because of < alignment
[编辑] 宽度和精度
宽度 是一个正十进制数,或一个嵌套的替换字段 ({}
或 {
n}
)。如果存在,它指定最小字段宽度。
精度 是一个点 (.
),后跟一个非负十进制数或一个嵌套的替换字段。此字段表示精度或最大字段大小。它只能与浮点类型和字符串类型一起使用。
- 对于浮点类型,此字段指定格式化精度。
- 对于字符串类型,它提供了要复制到输出的字符串前缀的估计宽度(见 下文)的上限。对于 Unicode 编码中的字符串,要复制到输出的文本是估计宽度不超过精度的最长完整扩展字形簇前缀。
如果嵌套替换字段用于 width 或 precision,并且相应的参数不是 整数类型(直到 C++23)标准有符号或无符号整数类型(从 C++23 起),或者为负数,则抛出类型为 std::format_error 的异常。
float pi = 3.14f; assert(std::format("{:10f}", pi) == " 3.140000"); // width = 10 assert(std::format("{:{}f}", pi, 10) == " 3.140000"); // width = 10 assert(std::format("{:.5f}", pi) == "3.14000"); // precision = 5 assert(std::format("{:.{}f}", pi, 5) == "3.14000"); // precision = 5 assert(std::format("{:10.5f}", pi) == " 3.14000"); // width = 10, precision = 5 assert(std::format("{:{}.{}f}", pi, 10, 5) == " 3.14000"); // width = 10, precision = 5 auto b1 = std::format("{:{}f}", pi, 10.0); // throws: width is not of integral type auto b2 = std::format("{:{}f}", pi, -10); // throws: width is negative auto b3 = std::format("{:.{}f}", pi, 5.0); // throws: precision is not of integral type
字符串的宽度定义为在终端中显示它所需的估计列数。
为了进行宽度计算,假设字符串使用实现定义的编码。宽度计算方法未指定,但对于使用 Unicode 编码的字符串,实现应该将字符串的宽度估计为其 扩展字形簇 中第一个代码点的估计宽度的总和。以下代码点的估计宽度为 2,否则为 1
- 任何代码点,其 Unicode 属性
East_Asian_Width
的值为 Fullwidth (F
) 或 Wide (W
) - U+4DC0 - U+4DFF (易经卦象)
- U+1F300 – U+1F5FF (各种符号和象形文字)
- U+1F900 – U+1F9FF (补充符号和象形文字)
assert(std::format("{:.^5s}", "🐱") == ".🐱.."); assert(std::format("{:.5s}", "🐱🐱🐱") == "🐱🐱"); assert(std::format("{:.<5.5s}", "🐱🐱🐱") == "🐱🐱.");
[编辑] L (特定于区域设置的格式)
L
选项会导致使用特定于区域设置的格式。此选项仅对算术类型有效。
- 对于整数类型,特定于区域设置的格式会根据上下文的区域设置插入适当的数字组分隔符字符。
- 对于浮点类型,特定于区域设置的格式会根据上下文的区域设置插入适当的数字组和基数分隔符字符。
- 对于
bool
的文本表示,特定于区域设置的格式会使用适当的字符串,就好像使用 std::numpunct::truename 或 std::numpunct::falsename 获得的字符串一样。
[编辑] 类型
type 选项确定数据应该如何呈现。
可用的字符串呈现类型为
- 无,
s
: 将字符串复制到输出。
|
(从 C++23 起) |
除 char、wchar_t 和 bool 之外的整数类型的可用整数呈现类型为
-
b
: 二进制格式。生成输出,就好像通过调用 std::to_chars(first, last, value, 2) 一样。基数前缀为0b
。 -
B
: 与b
相同,只是基数前缀为0B
。 -
c
: 将字符 static_cast<CharT>(value) 复制到输出,其中CharT
是格式字符串的字符类型。如果 value 不在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
相同。
可用的 char 和 wchar_t 呈现类型为
- 无,
c
: 将字符复制到输出。 -
b
、B
、d
、o
、x
、X
: 使用整数呈现类型,其值为 static_cast<unsigned char>(value) 或 static_cast<std::make_unsigned_t<wchar_t>>(value),分别。
|
(从 C++23 起) |
可用的 bool 呈现类型为
- 无,
s
: 将文本表示 (true
或false
,或特定于区域设置的格式) 复制到输出。 -
b
、B
、d
、o
、x
、X
: 使用整数呈现类型,其值为 static_cast<unsigned char>(value)。
可用的浮点呈现类型为
-
a
: 如果指定了 precision,则生成输出,就好像通过调用 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
表示指数。 - 无: 如果指定了 precision,则生成输出,就好像通过调用 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::nullptr_t) 为
- 无,
p
: 如果定义了 std::uintptr_t,则生成输出,就好像通过调用 std::to_chars(first, last, reinterpret_cast<std::uintptr_t>(value), 16) 一样,并向输出添加前缀0x
;否则,输出由实现定义。
|
(从 C++26 起) |
格式化转义字符和字符串可以将字符或字符串格式化为 转义,使其更适合调试或记录。 转义的执行方式如下
字符串的转义字符串表示是通过转义字符串中的代码单元序列(如上所述)并用双引号引起来构建的。 字符的转义表示是通过如上所述对其进行转义并用单引号引起来构建的。 运行这段代码 #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}".
特性测试 宏 | 值 | Std | 特性 |
---|---|---|---|
__cpp_lib_format_uchar |
202311L | (C++20) (DR) |
代码单元的格式化为无符号整数 |
[编辑] 缺陷报告
以下更改行为的缺陷报告被追溯应用于以前发布的 C++ 标准。
DR | 应用于 | 发布的行为 | 正确行为 |
---|---|---|---|
LWG 3721 | C++20 | 宽度字段不允许为零 在标准格式规范中 |
如果通过替换字段指定,则允许为零 |
P2909R4 | C++20 | char 或 wchar_t 可能被格式化为 超出范围的无符号整数值 |
代码单元在进行此类格式化之前被转换为相应的 无符号类型 |