c++ {fmt} library usage guide 1

1. Origin

It was late at night, and the hour hand quietly came to eleven-thirty, but my thoughts were surging like a spring, and I couldn't sleep at all. At this time, I was eager to do something meaningful, and decided to take advantage of this tranquility to calm down and write a guide on the use of the fmt library.
The fmt library is an efficient and easy-to-use C++ formatting library that can help us conveniently perform string formatting, output, logging and other operations. In this guide, I will introduce the basic usage of the fmt library, formatted string syntax, exception handling mechanism, etc., hoping to help everyone. Let’s get started!

2. Basic use

Install fmt library

github: https://github.com/fmtlib/fmt
api guide: https://fmt.dev/latest/api.html

Introduce fmt library into the project
  1. The old method cmake (not recommended)
    mkdir build
    cd build
    cmake ...
    make or use IDE to open the generated project file to generate the corresponding library static library\
  2. Only include header files, (need to #define FMT_HEADER_ONLY before including header files recommended)
    • fmt/core.h: The main formatting function of char/UTF-8, supports C++20 compile-time checking, and minimizes dependencies.
    • fmt/format.h: Complete formatting API, in addition to additional formatting functions, supports localization (multi-language support).
    • fmt/ranges.h: Format ranges and tuples
    • fmt/chrono.h: Date and time formatting.
    • fmt/std.h: formatting support for c++ standard library types.
    • fmt/compile.h: Compilation of format strings (compile-time format string detection). FMT_STRING(s)
    • fmt/color.h: terminal color and text style.
    • fmt/os.h: Provides system API.
    • fmt/ostream.h: Support std::ostream.
    • fmt/printf.h: supports printf formatting.
    • fmt/xchar.h: Optional wchar_t support.

Hello World

    #define FMT_HEADER_ONLY 
    #include "fmt/core.h"
    #include <string>
    int main()
    {
    
    
        // {} 占位符,可以占位int float double ....
        std::string world = fmt::format("Hello {}", "World");
        fmt::print("{}", world);
    }

3. Character formatting syntax

Formatting functions such as fmt::format() and fmt::print() all use the same syntax, which is a "replacement field" surrounded by {}.
Anything not enclosed in curly braces is treated as literal text and will be copied to the output without modification. If you need to include a brace character in literal text, you can escape it by repeating the brace: { { and }}.
In most cases, the syntax is similar to the printf format, but {} is added and : is used instead of %. For example, "%03.2f" can be converted to "{:03.2f}", just replacing % with {}, but fmt is more powerful. The
output format is as follows:
replacement_field ::= "{" [arg_id] [":" (format_spec | chrono_format_spec)] “}” // Replacement character = {[parameter id]:[format_spec] | [chrono_format_spec]}
arg_id ::= integer | identifier // Integer 0-9 az AZ, the following indicates which one means what
integer ::= digit+
digit ::= “0”…“9”
identifier ::= id_start id_continue*
id_start ::= “a”…“z” | “A”…“Z” | “_”
id_continue ::= id_start | digit\

The replacement format uses ":" as the delimiter. The one before ":" represents the parameter id, which refers to the order of the parameters. It can be 1, 2, 3, 4,... or it can be a, b, c... after ":" is a format specifically defined for numeric (integer, floating point) time types. [] represents optional, | represents or, only one can exist

3.1 Parameter id is before ":"

    // 只有参数id时候,: 可以省略不写
    fmt::print("name:{1}, age: {0:}", 42, "knox");

3.2format_spec after ":" (Format Specification Mini-Language format specification mini language)

  1. 组成
    format_spec ::= [[fill]align][sign][“#”][“0”][width][“.” precision][“L”][type]
    fill ::= <a character other than ‘{’ or ‘}’>
    align ::= “<” | “>” | “^”
    sign ::= “+” | “-” | " "
    width ::= integer | “{” [arg_id] “}”
    precision ::= integer | “{” [arg_id] “}”
    type ::= “a” | “A” | “b” | “B” | “c” | “d” | “e” | “E” | “f” | “F” | “g” | “G” |
    “o” | “p” | “s” | “x” | “X”\

  2. file represents the padding character, which can be any Unicode code point except "{" and "}". The presence of a pad character is indicated by the character that follows it, which must be one of the alignment options. If the second character of format_spec is not a valid alignment option (<, >, ^), neither pad characters nor alignment options are assumed to be present.

  3. align represents alignment, < represents left alignment, > represents right alignment, ^ represents centering

  4. sign is only for numbers, "+" means that both positive and negative numbers use signs. "-" means that only negative numbers require a sign (this is the default behavior). A space means that a space must be added before a positive number, and a minus sign must be added before a negative number.

  5. This option is only available for integer and floating point types. For integers, when using binary, octal, or hexadecimal output, this option adds the appropriate prefix "0b" ("0B"), "0", or "0x" ("0X") to the output value, The lowercase character format is lowercase, such as {:#0X}, 255 = 0XFF, , {:#0x}, 255 = 0xff, other bases are similar,

  6. width is a decimal integer, only applicable to numeric types, used to define the minimum field width. If not specified, the field width will be determined by the content. Preceding the width field with a zero ('0') character enables sign-aware zero padding for numeric types.
    It forces padding to be placed after the sign or base (if any) but before the number. This is used to print the field in the form "+000000120".

  7. "." precision represents precision. Precision only exists in floating point types. Integers, characters, Boolean and pointer values ​​are not allowed to use precision. For non-numeric types, the field indicates the maximum field size, even if the size is specified. C strings must be terminated with a null character.
    The general precision.nf, not the precision.nn, represents several formats that need to be formatted.

    // 非数字指定的是输出的字符的个数。
    fmt::print("name:{1}, age: {0:.5}", "1234567890", "knox");
    // 输出:name:knox, age: 12345
    
    // c字符串不够怎么办呢,最大字符串长
    fmt::print("name:{1}, age: {0:.5}", "123", "knox");
    // 输出:name:knox, age: 123
    
    // 对于数字代表精度,只对浮点型有用
    fmt::print("{:.2f}", 42.0f);
    // 输出:42.00
    //fmt::print("{:.2f}", 42); 编译报错
    //fmt::print("{:.2f}", true); 编译报错

  1. The "L" option uses the current locale to insert appropriate number separators. This option is only available for numeric types.
    auto s = fmt::format(std::locale("en_US.UTF-8"), "{:L}", 1234567890);
    fmt::print("{}", s);
    // 输出: 1,234,567,890
  1. type
    'e' exponential notation. The index notation uses the lowercase letter 'e'.
    'E' index notation. Index notation uses a capital letter 'E'.
    'f' fixed-point notation. Display numbers as fixed-point numbers.
    'F' fixed-point notation. Display numbers as fixed-point numbers. Same as 'f'.
    'g' general format. Depending on the size of the number and the specified precision, either fixed-point or exponential notation is used.
    'G' general format. Same as 'g', but uses an uppercase 'E' for index notation.
    'x' hexadecimal integer. Display numbers as hexadecimal numbers.
    'X' hexadecimal integer. Display numbers as uppercase hexadecimal numbers.
    'a' hexadecimal floating point number. Use lowercase 'a' for index notation.
    'A' hexadecimal floating point number. Use capital letter 'A' for index notation.
    'c' character. Interpret integers as Unicode characters.
    's' string. Format parameters as strings.
    'p' pointer. Format pointer as hexadecimal number.

chrono_format_spec time formatting

1. Composition
chrono_format_spec ::= [[fill]align][width][“.” precision][chrono_specs]
chrono_specs ::= [chrono_specs] conversion_spec | chrono_specs literal_char
conversion_spec ::= “%” [modifier] chrono_type
literal_char :: = <a character other than '{', '}' or '%'>\ // Except { } %, these three characters can be used as link character
modifier::= “E” | “O”
chrono_type ::= “ a" | "A" | "b" | "B" | "c" | "C" | "d" | "D" | "e" | "F" | "g" | "G" | "h
" | "H" | "I" | "j" | "m" | "M" | "n" | "p" | "q" | "Q" | "r" | "R" | "S" |
" t" | "T" | "u" | "U" | "V" | "
w" | "W" | "x" | "X" | "y" | "Y" | "z" | "Z" | "%"\

  1. [[fill]align] Similar to 3.2.1
  2. If the number of days is less than 10, the number of minutes, seconds, or months will be added with 0 in front.
    For more detailed syntax of fmt format string, please go to https://fmt.dev/latest/syntax.html#grammar-token-sf -identifier

Format string example

Output in order of arg_id, id starts from 0
    // 序号从零开始
    fmt::print("{0}, {1}, {2}\n", 'a', 'b', 'c');
    // print: "a, b, c"


    fmt::print("{}, {}, {}\n", 'a', 'b', 'c');
    // print: "a, b, c"

    fmt::print("{2}, {1}, {0} \n", 'a', 'b', 'c');
    // print: "c, b, a"
    // fmt::print("{2}, {1}, {0} {3}\n", 'a', 'b', 'c'); 编译报错,没有第四个参数

    // 输出
    // a, b, c  
    // a, b, c  
    // c, b, a  
Fill the blanks with custom characters and specify the centering method
    // 不指定填充符号默认为空格, 如果不存在 <>^ 就假定填充符号都不存在
    fmt::print("{:<30}\n", "left aligned");
    // 
    fmt::print("{:<<30}\n", "left aligned");
                
    fmt::print("{:>30}\n", "right aligned");
    fmt::print("{:>>30}\n", "right aligned");

    fmt::print("{:^30}\n", "centered");
          
    fmt::print("{:^^30}\n", "centered"); 

    // 输出
    //left aligned                  
    //left aligned<<<<<<<<<<<<<<<<<<
    //                right aligned 
    //>>>>>>>>>>>>>>>>>right aligned
    //        centered              
    //^^^^^^^^^^^centered^^^^^^^^^^^

Dynamically set width and precision
    // 可以动态设置宽度和精度,但仅仅限制于此,
    // 动态设置宽度的时候,宽度arg_id 为 参数+1, 
    //           0 1   2 3  参数arg_id 可以数{ 的个数,当然{} 一定是成对出现的。
    fmt::print("{:<{}} {:.{}f} \n", "left aligned", 30, 3.14, 1);
    fmt::print("{:.{}f}\n", 3.14, 1);
    // 输出
    // left aligned                   3.1  
    // 3.1  

Use of :+ :- sign
    // + 代表正数加+号,负数加-号
    fmt::print("{:+f}; {:+f}\n", 3.14, -3.14); 
    // 空格正数加空格,负数加-号
    fmt::print("{: f}; {: f}\n", 3.14, -3.14); 
    // -号代表正数不变,负数加-号 same as '{:f}; {:f}' 相当于是默认行为
    fmt::print("{:-f}; {:-f}\n", 3.14, -3.14);

    fmt::print("{:+}; {:+}\n", 3, -3);
    fmt::print("{:-}; {:-}\n", 3, -3);
    fmt::print("{: }; {: }\n", 3, -3);
    fmt::print("{:}; {:}\n", 3, -3);

    // 输出
    //+3.140000; -3.140000
    // 3.140000; -3.140000
    //3.140000; -3.140000
    //+3; -3
    //3; -3
    // 3; -3
    //3; -3
hexadecimal output
    // # 加上符号 0x 0 0b
    fmt::print("int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}\n", 42);
    
    fmt::print("int: {0:d};  hex: {0:#x};  oct: {0:#o};  bin: {0:#b}\n", 42);

    // #06 代表宽度为6个, 不够的在进制之前使用0填充, 超出指定大小被忽略
    fmt::print("int: {0:d};  hex: {0:#06x};  oct: {0:#06o};  bin: {0:#06b}\n", 42);
    fmt::print("int: {0:d};  hex: {0:#01x};  oct: {0:#02o};  bin: {0:#03b}\n", 42);
    // 输出
    // int: 42;  hex: 2a;  oct: 52; bin: 101010
    // int: 42;  hex: 0x2a;  oct: 052;  bin: 0b101010
    // int: 42;  hex: 0x002a;  oct: 000052;  bin: 0b101010
    // int: 42;  hex: 0x2a;  oct: 052;  bin: 0b101010
Print borders using fill characters
    fmt::print(
        "┌{0:─^{2}}┐\n"
        "│{1: ^{2}}│\n"
        "└{0:─^{2}}┘\n", "", "Hello, knox!", 20);

I can’t resist anymore, so I’ll stop here today. Tomorrow we will continue with the detailed usage of the fmt library’s API.

Guess you like

Origin blog.csdn.net/qq_33944628/article/details/129943438