Standard format specification (since C++20)
对于基础类型和字符串类型,格式规范基于 Python中的格式规范 。
格式规范的语法如下:
填充与对齐
(可选)
符号
(可选)
#
(可选)
0
(可选)
宽度
(可选)
精度
(可选)
L
(可选)
类型
(可选)
|
|||||||||
当使用整数或浮点数表示类型时,
sign
、
#
和
0
选项才有效。
目录 |
填充与对齐
fill-and-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
字符和
对齐
选项,则忽略
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
}
)。如果存在,它指定最小字段宽度。
精度
是一个点(
.
)后跟一个非负十进制数或嵌套替换字段。该字段表示精度或最大字段大小。它只能用于浮点数和字符串类型。
- 对于浮点数类型,此字段指定格式化精度。
- 对于字符串类型,它提供了待复制到输出的字符串前缀估计宽度的上限(参见 下文 )。对于Unicode编码的字符串,将被复制到输出的文本是完整扩展字符簇的最长前缀,其估计宽度不超过精度值。
如果对 width 或 precision 使用了嵌套替换字段,且对应参数不是 整数类型 (C++23 前) 标准有符号或无符号整数类型 (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:
-
任何Unicode属性
East_Asian_Width值为全角(F)或宽形(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是格式字符串的字符类型。若数值不在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 表示类型包括:
-
none,
c: 将字符复制到输出。 -
b,B,d,o,x,X: 使用整数表示类型,其值为 static_cast < unsigned char > ( value ) 或 static_cast < std:: make_unsigned_t < wchar_t >> ( value ) 。
|
(since C++23) |
可用的 bool 表示类型包括:
-
无,
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;否则,输出由实现定义。
|
(since C++26) |
转义字符与字符串的格式化字符或字符串可格式化为 转义 形式,使其更适用于调试或日志记录。 转义规则如下:
字符串的转义表示通过转义字符串中的码元序列(如上所述)并用双引号包裹结果来构造。 字符的转义表示通过转义该字符(如上所述)并用单引号包裹结果来构造。
运行此代码
#include <print> int main() { std::println("[{:?}]", "h\tllo"); // 输出: ["h\tllo"] std::println("[{:?}]", "Спасибо, Виктор ♥!"); // 输出: ["Спасибо, Виктор ♥!"] std::println("[{:?}] [{:?}]", '\'', '"'); // 输出: ['\'', '"'] // 以下示例假设使用UTF-8编码 std::println("[{:?}]", std::string("\0 \n \t \x02 \x1b", 9)); // 输出: ["\u{0} \n \t \u{2} \u{1b}"] std::println("[{:?}]", "\xc3\x28"); // 无效UTF-8 // 输出: ["\x{c3}("] std::println("[{:?}]", "\u0301"); // 输出: ["\u{301}"] std::println("[{:?}]", "\\\u0301"); // 输出: ["\\\u{301}"] std::println("[{:?}]", "e\u0301\u0323"); // 输出: ["ẹ́"] } |
(C++23 起) |
注释
在大多数情况下,新语法与旧的
%
格式化方式类似,增加了
{}
的使用,并用
:
替代
%
。例如,
"%03.2f"
可转换为
"{:03.2f}"
。
| 功能测试 宏 | 值 | 标准 | 功能 |
|---|---|---|---|
__cpp_lib_format_uchar
|
202311L
|
(C++20)
(DR) |
将代码单元格式化为无符号整数 |
缺陷报告
下列行为变更缺陷报告被追溯应用于先前发布的 C++ 标准。
| 缺陷报告 | 适用标准 | 发布时行为 | 正确行为 |
|---|---|---|---|
| LWG 3721 | C++20 |
标准格式规范中宽度字段
不允许使用零值 |
若通过替换字段指定
则允许使用零值 |
| P2909R4 | C++20 |
char
或
wchar_t
可能被格式化为
超出范围的无符号整数值 |
在进行此类格式化前,代码单元
会先转换为对应的无符号类型 |