名稱空間
變體
操作

標準格式規範 (C++20 起)

來自 cppreference.com
< cpp‎ | 工具‎ | 格式化
 
 
 
 

對於基本型別和字串型別,格式規範基於 Python 中的格式規範

格式規範的語法是

填充和對齊 (可選) 符號 (可選) #(可選) 0(可選) 寬度 (可選) 精度 (可選) L(可選) 型別 (可選)

符號#0 選項僅在使用整數或浮點表示型別時有效。

目錄

[編輯] 填充和對齊

fill-and-align 是一個可選的填充字元(可以是除 {} 之外的任何字元),後跟對齊選項 <>^ 之一。

如果未指定填充字元,則預設為空格字元。對於 Unicode 編碼中的格式規範,填充字元必須對應於單個 Unicode 標量值。

對齊選項的含義如下

  • <: 透過在格式化引數後插入 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");
}

# 選項導致轉換使用備用形式

  • 對於整數型別,當使用二進位制、八進位制或十六進位制表示型別時,備用形式在輸出值中符號字元(可能為空格)之後插入字首(0b00x),如果存在的話,否則在輸出值之前新增它。
  • 對於浮點型別,備用形式導致有限值的轉換結果始終包含小數點字元,即使後面沒有數字。通常,小數點字元僅在後面有數字時才出現在這些轉換的結果中。此外,對於 gG 轉換,不會從結果中移除尾隨零。

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 is ignored because of '<'
}

[編輯] 寬度和精度

width 是一個正十進位制數,或一個巢狀替換欄位({}{n})。如果存在,它指定最小欄位寬度。

precision 是一個點(.),後跟一個非負十進位制數或一個巢狀替換欄位。此欄位表示精度或最大欄位大小。它只能與浮點和字串型別一起使用。

  • 對於浮點型別,此欄位指定格式化精度。
  • 對於字串型別,它為要複製到輸出的字串字首的估計寬度(參見下文)提供上限。對於 Unicode 編碼中的字串,要複製到輸出的文字是最長的字首,由完整擴充套件字素簇組成,其估計寬度不大於精度。

如果 widthprecision 使用巢狀替換欄位,且相應引數不是整型(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 值為全形 (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::truenamestd::numpunct::falsename 獲得。

[編輯] 型別

type 選項確定資料應如何呈現。

可用的字串表示型別為

  • 無, s: 將字串複製到輸出。
  • ?: 將跳脫字元串(參見下文)複製到輸出。
(C++23 起)

charwchar_tbool 之外的整型可用的整數表示型別為

  • 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 相同。

可用的 charwchar_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: 將文字表示(truefalse,或區域設定特定形式)複製到輸出。
  • 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 分別格式化為 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_Category 的值為 Separator (Z) 或 Other (C) 組中的值,或者
  • C 前面沒有緊跟非跳脫字元,並且 C 對應於一個具有 Unicode 屬性 Grapheme_Extend=Yes 的 Unicode 標量值,或者
  • 關聯的字元編碼不是 Unicode 編碼,並且 C 是實現定義的若干分隔符或不可列印字元之一
轉義序列是 \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++ 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
LWG 3721 C++20 寬度欄位不允許為零
在標準格式規範中
如果透過替換欄位指定,則允許為零
透過替換欄位
P2909R4 C++20 charwchar_t 可能格式化為
超出範圍的無符號整數值
程式碼單元在進行此類格式化之前轉換為相應的無符號型別
無符號型別